|
Mixe for Privacy and Anonymity in the Internet
|
This is the AI (accounting instance or abrechnungsinstanz in german) class. More...
#include <CAAccountingInstance.hpp>
Classes | |
| struct | t_aiqueueitem |
Static Public Member Functions | |
| static SINT32 | init (CAFirstMix *callingMix) |
| Returns a reference to the Singleton instance. | |
| static SINT32 | clean () |
| static UINT32 | getAuthFlags (fmHashTableEntry *pHashEntry) |
| static SINT32 | cleanupTableEntry (fmHashTableEntry *pHashEntry) |
| This should always be called when closing a JAP connection to cleanup the data structures. | |
| static SINT32 | initTableEntry (fmHashTableEntry *pHashEntry) |
| This must be called whenever a JAP is connecting to init our per-user data structures. | |
| static SINT32 | handleJapPacket (fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP) |
| This should be called by the FirstMix for every incoming Jap packet. | |
| static SINT32 | isIPAddressBlocked (const UINT8 ip[4]) |
| Check if an IP address is temporarily blocked by the accounting instance. | |
| static SINT32 | processJapMessage (fmHashTableEntry *pHashEntry, const XERCES_CPP_NAMESPACE::DOMDocument *a_DomDoc) |
| Handle a user (xml) message sent to us by the Jap through the ControlChannel. | |
| static UINT32 | getNrOfUsers () |
| static SINT32 | loginProcessStatus (fmHashTableEntry *pHashEntry) |
| static SINT32 | finishLoginProcess (fmHashTableEntry *pHashEntry) |
| this method is for the corresponding CAFirstMix login thread to verify the result of the settlement. | |
| static SINT32 | settlementTransaction () |
| static SettleEntry * | __handleSettleResult (CAXMLCostConfirmation *pCC, CAXMLErrorMessage *pErrMsg, CAAccountingDBInterface *dbInterface, UINT64 a_iSettlementTransactionNr) |
| static void | __commitSettlementToDatabase (SettleEntry *entryList, CAAccountingDBInterface *dbInterface) |
| only for internal use during the settleTransaction because the global settlement lock is not acquired | |
| static void | __commitSettlementToLoginTable (SettleEntry *entryList) |
| only for internal use during the settleTransaction because no login table locks are acquired | |
| static SINT32 | newSettlementTransaction () |
| static SINT32 | __newSettlementTransaction (UINT32 *nrOfSettledCCs) |
Static Public Attributes | |
| static const SINT32 | HANDLE_PACKET_CONNECTION_OK = 1 |
| static const SINT32 | HANDLE_PACKET_CONNECTION_UNCHECKED = 4 |
| static const SINT32 | HANDLE_PACKET_HOLD_CONNECTION = 0 |
| static const SINT32 | HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION = 2 |
| static const SINT32 | HANDLE_PACKET_CLOSE_CONNECTION = 3 |
| static const UINT32 | MAX_SETTLED_CCS = 10 |
Private Types | |
| typedef struct t_aiqueueitem | aiQueueItem |
Private Member Functions | |
| CAAccountingInstance (CAFirstMix *callingMix) | |
| private Constructor | |
| ~CAAccountingInstance () | |
| private destructor | |
| UINT32 | handleCostConfirmation (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Handles a cost confirmation sent by a jap. | |
| UINT32 | handleCostConfirmation_internal (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Handles a cost confirmation sent by a jap. | |
| UINT32 | handleAccountCertificate (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Handles an account certificate of a newly connected Jap. | |
| UINT32 | handleAccountCertificate_internal (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Handles an account certificate of a newly connected Jap. | |
| UINT32 | handleChallengeResponse (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Checks the response of the challenge-response auth. | |
| UINT32 | handleChallengeResponse_internal (tAiAccountingInfo *pAccInfo, DOMElement *root) |
| Handles the response to our challenge. | |
| bool | cascadeMatchesCC (CAXMLCostConfirmation *pCC) |
| SINT32 | prepareCCRequest (CAMix *callingMix, UINT8 *a_AiName) |
| creating the xml of a new CC is really the responsability of the CAXMLCostConfirmation class knowledge about the structure of a CC's XML should be encapsulated in it TODO: add constructor to that class that takes accountnumber, transferredbytes etc as params (should use a template internally into which it only inserts accNumber and bytes,to speed things up TODO: add toXMLElement method then replace manually building the xml here with contructing a CAXMLCostConfirmation and just add the xml returned by its toXMLElement method | |
Static Private Member Functions | |
| static SINT32 | handleJapPacket_internal (fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP) |
| Called by FirstMix for each incoming JAP packet. | |
| static UINT64 | unlockLogin (fmHashTableEntry *ownerRef) |
| release login (particularly for use in error case) this function is thread-safe. | |
| static void | processJapMessageLoginHelper (fmHashTableEntry *pHashEntry, UINT32 handlerReturnvalue, bool finishLogin) |
| static SINT32 | getPrepaidBytes (tAiAccountingInfo *pAccInfos) |
| static SINT32 | makeInitialCCRequest (CAXMLCostConfirmation *pCC, XERCES_CPP_NAMESPACE::DOMDocument *&doc, SINT32 prepaidBytes) |
| new initialCCRequest containing the last CC and the prepaid bytes (this is a replacement for sending the prepaid with the challenge which is now deprecated). | |
| static SINT32 | makeCCRequest (const UINT64 accountNumber, const UINT64 transferredBytes, XERCES_CPP_NAMESPACE::DOMDocument *&doc) |
| static SINT32 | sendInitialCCRequest (tAiAccountingInfo *pAccInfo, CAXMLCostConfirmation *pCC, SINT32 prepaidBytes) |
| static SINT32 | sendCCRequest (tAiAccountingInfo *pAccInfo) |
| static SINT32 | makeAccountRequest (XERCES_CPP_NAMESPACE::DOMDocument *&doc) |
| static SINT32 | sendAILoginConfirmation (tAiAccountingInfo *pAccInfo, const UINT32 code, UINT8 *message) |
| static SINT32 | returnKickout (tAiAccountingInfo *pAccInfo) |
| When receiving this message, the Mix should kick the user out immediately. | |
| static SINT32 | returnPrepareKickout (tAiAccountingInfo *pAccInfo, CAXMLErrorMessage *a_error) |
| static void | setPrepaidBytesToZero (tAiAccountingInfo *pAccInfo) |
| static void | setPrepaidBytesToZero_internal (tAiAccountingInfo *pAccInfo) |
| static THREAD_RETURN | processThread (void *a_param) |
| The main loop of the AI thread - reads messages from the queue and starts process threads for these messages. | |
Private Attributes | |
| CAThreadPool * | m_aiThreadPool |
| reads messages from the queue and processes them | |
| CAMutex * | m_pMutex |
| this is for synchronizing the write access to the HashEntries | |
| Hashtable * | m_certHashCC |
| Hashtable * | m_currentAccountsHashtable |
| Stores the account number of all users currently logged in. | |
| CAFirstMix * | m_mix |
| UINT8 * | m_AiName |
| the name of this accounting instance | |
| UINT8 * | m_currentCascade |
| current cascade (identified by the concatenated hash values of the price certificates) | |
| UINT8 ** | m_allHashes |
| The hash values of the Mixes ordered beginning with the AI Mix. | |
| UINT32 | m_allHashesLen |
| CAAccountingBIInterface * | m_pPiInterface |
| the interface to the database | |
| UINT32 | m_iSoftLimitBytes |
| UINT32 | m_iHardLimitBytes |
| CATempIPBlockList * | m_pIPBlockList |
| Users that get kicked out because they sent no authentication certificate get their IP appended to this list. | |
| CAAccountingSettleThread * | m_pSettleThread |
| Signature verifying instance for BI signatures. | |
| bool | m_bThreadRunning |
| volatile UINT64 | m_nextSettleNr |
| volatile UINT64 | m_settleWaitNr |
| CAConditionVariable * | m_pSettlementMutex |
| volatile UINT32 | m_seqBIConnErrors |
Static Private Attributes | |
| static const UINT64 | PACKETS_BEFORE_NEXT_CHECK = 100 |
| static const UINT32 | MAX_TOLERATED_MULTIPLE_LOGINS = 10 |
| static XERCES_CPP_NAMESPACE::DOMDocument * | m_preparedCCRequest |
| static CAAccountingInstance * | ms_pInstance = NULL |
| Singleton: This is the reference to the only instance of this class. | |
| static SINT32 | m_prepaidBytesMinimum = 0 |
| static volatile UINT64 | m_iCurrentSettleTransactionNr = 0 |
Friends | |
| class | CAFirstMixA |
| class | CAFirstMix |
This is the AI (accounting instance or abrechnungsinstanz in german) class.
Its purpose is to count packets for every user and to decide wether the connection should be closed (e.g. when a user is betraying us, or simply when the account is empty and the user refuses to charge it).
It is a singleton class, only one instance exists at a time. On the first call to getInstance() the initialization is performed.
Definition at line 112 of file CAAccountingInstance.hpp.
typedef struct t_aiqueueitem CAAccountingInstance::aiQueueItem [private] |
Definition at line 215 of file CAAccountingInstance.hpp.
| CAAccountingInstance::CAAccountingInstance | ( | CAFirstMix * | callingMix | ) | [private] |
private Constructor
Definition at line 77 of file CAAccountingInstance.cpp.
References Hashtable::compareUINT64(), CACmdLnOptions::getAiID(), CALibProxytest::getOptions(), CACmdLnOptions::getPaymentHardLimit(), CACmdLnOptions::getPaymentSoftLimit(), Hashtable::hashUINT64(), m_AiName, m_aiThreadPool, m_allHashes, m_allHashesLen, m_certHashCC, m_currentAccountsHashtable, m_currentCascade, m_iHardLimitBytes, m_iSoftLimitBytes, m_mix, m_nextSettleNr, m_pMutex, m_pPiInterface, m_pSettlementMutex, m_pSettleThread, m_seqBIConnErrors, m_settleWaitNr, MAX_LOGIN_QUEUE, NUM_LOGIN_WORKER_TRHEADS, prepareCCRequest(), CAMsg::printMsg(), Hashtable::put(), CAAccountingBIInterface::setPIServerConfiguration(), Hashtable::stringCompare(), and Hashtable::stringHash().
Referenced by init().
{
CAMsg::printMsg( LOG_DEBUG, "AccountingInstance initialising\n" );
m_seqBIConnErrors = 0;
m_pMutex = new CAMutex();
//m_pIPBlockList = new CATempIPBlockList(60000);
m_pSettlementMutex = new CAConditionVariable();
//m_loginHashTableChangeInProgress = false; //for synchronizing settlementTransactions of loginThreads and SettlementThread.
m_nextSettleNr = 0; //The next thread's number to alter the login hash table
m_settleWaitNr = 0; //The wait number when it is equal to nextSettle number it's the thread's turn has to to
//alter the login hash table
// initialize Database connection
//m_dbInterface = new CAAccountingDBInterface();
m_pPiInterface = new CAAccountingBIInterface();
m_mix = callingMix;
/*if(m_dbInterface->initDBConnection() != E_SUCCESS)
{
CAMsg::printMsg( LOG_ERR, "**************** AccountingInstance: Could not connect to DB!\n");
exit(1);
}*/
// initialize JPI signature tester
m_AiName = new UINT8[256];
CALibProxytest::getOptions()->getAiID(m_AiName, 256);
if (CALibProxytest::getOptions()->getBI() != NULL)
{
//m_pJpiVerifyingInstance = CALibProxytest::getOptions()->getBI()->getVerifier();
m_pPiInterface->setPIServerConfiguration(CALibProxytest::getOptions()->getBI());
}
m_iHardLimitBytes = CALibProxytest::getOptions()->getPaymentHardLimit();
m_iSoftLimitBytes = CALibProxytest::getOptions()->getPaymentSoftLimit();
prepareCCRequest(callingMix, m_AiName);
m_currentAccountsHashtable =
new Hashtable((UINT32 (*)(void *))Hashtable::hashUINT64, (SINT32 (*)(void *,void *))Hashtable::compareUINT64, 2000);
m_certHashCC =
new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
for (UINT32 i = 0; i < m_allHashesLen; i++)
{
m_certHashCC->put(m_allHashes[i], m_allHashes[i]);
}
// launch BI settleThread
m_pSettleThread = new CAAccountingSettleThread(m_currentAccountsHashtable,
m_currentCascade);
m_aiThreadPool = new CAThreadPool(NUM_LOGIN_WORKER_TRHEADS, MAX_LOGIN_QUEUE, false);
}
| CAAccountingInstance::~CAAccountingInstance | ( | ) | [private] |
private destructor
Definition at line 132 of file CAAccountingInstance.cpp.
References BEGIN_STACK, Hashtable::clear(), FINISH_STACK, Hashtable::getMutex(), HASH_EMPTY_DELETE, HASH_EMPTY_NONE, INIT_STACK, CAMutex::lock(), m_AiName, m_aiThreadPool, m_allHashes, m_allHashesLen, m_certHashCC, m_currentAccountsHashtable, m_currentCascade, m_pMutex, m_pPiInterface, m_pSettlementMutex, m_pSettleThread, CAMsg::printMsg(), Hashtable::remove(), and CAMutex::unlock().
{
INIT_STACK;
BEGIN_STACK("~CAAccountingInstance");
/*
* avoid calling this desctructor concurrently!
*/
m_pMutex->lock();
CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying\n" );
if (m_pSettleThread)
{
CAMsg::printMsg( LOG_DEBUG, "deleting m_pSettleThread\n" );
//m_pSettleThread->settle();
delete m_pSettleThread;
m_pSettleThread = NULL;
}
if (m_aiThreadPool)
{
CAMsg::printMsg( LOG_DEBUG, "deleting m_aiThreadPool\n" );
delete m_aiThreadPool;
m_aiThreadPool = NULL;
}
/*if (m_dbInterface)
{
CAMsg::printMsg( LOG_DEBUG, "termintaing dbConnection\n" );
m_dbInterface->terminateDBConnection();
delete m_dbInterface;
}
m_dbInterface = NULL;*/
delete m_pPiInterface;
m_pPiInterface = NULL;
delete m_pSettlementMutex;
m_pSettlementMutex = NULL;
//delete m_pIPBlockList;
//m_pIPBlockList = NULL;
delete[] m_AiName;
m_AiName = NULL;
if (m_currentAccountsHashtable)
{
m_currentAccountsHashtable->getMutex()->lock();
CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Clearing accounts hashtable...\n");
m_currentAccountsHashtable->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Deleting accounts hashtable...\n" );
m_currentAccountsHashtable->getMutex()->unlock();
delete m_currentAccountsHashtable;
m_currentAccountsHashtable = NULL;
}
m_currentAccountsHashtable = NULL;
CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Accounts hashtable deleted.\n" );
delete[] m_currentCascade;
m_currentCascade = NULL;
if(m_certHashCC != NULL)
{
for (UINT32 i = 0; i < m_allHashesLen; i++)
{
UINT8* certHash = (UINT8*)m_certHashCC->remove(m_allHashes[i]);
}
m_certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
delete m_certHashCC;
m_certHashCC = NULL;
}
if (m_allHashes)
{
for (UINT32 i = 0; i < m_allHashesLen; i++)
{
delete m_allHashes[i];
m_allHashes[i] = NULL;
}
delete[] m_allHashes;
}
m_allHashes = NULL;
m_pMutex->unlock();
delete m_pMutex;
m_pMutex = NULL;
FINISH_STACK("~CAAccountingInstance");
CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying finished.\n" );
}
| void CAAccountingInstance::__commitSettlementToDatabase | ( | SettleEntry * | entryList, |
| CAAccountingDBInterface * | dbInterface | ||
| ) | [static] |
only for internal use during the settleTransaction because the global settlement lock is not acquired
Definition at line 3198 of file CAAccountingInstance.cpp.
References SettleEntry::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_INVALID_ACCOUNT, AUTH_UNKNOWN, SettleEntry::authFlags, SettleEntry::authRemoveFlags, CAAccountingDBInterface::clearAccountStatus(), SettleEntry::diffBytes, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAAccountingDBInterface::getPrepaidAmount(), m_currentCascade, ms_pInstance, SettleEntry::nextEntry, CAMsg::printMsg(), SettleEntry::storedStatus, and CAAccountingDBInterface::storePrepaidAmount().
Referenced by __newSettlementTransaction().
{
SettleEntry *entry = entryList, *nextEntry = NULL;
while (entry != NULL && dbInterface != NULL)
{
if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
{
dbInterface->storePrepaidAmount(
entry->accountNumber, 0, ms_pInstance->m_currentCascade);
}
else if (entry->diffBytes)
{
// user is currently not logged in; set correct prepaid bytes in DB
SINT32 prepaidBytes =
dbInterface->getPrepaidAmount(entry->accountNumber,
ms_pInstance->m_currentCascade, true);
if (prepaidBytes > 0)
{
if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
{
prepaidBytes = 0;
}
else
{
prepaidBytes -= entry->diffBytes;
}
dbInterface->storePrepaidAmount(
entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
}
}
if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
entry->storedStatus != 0)
{
dbInterface->clearAccountStatus(entry->accountNumber);
switch (entry->storedStatus)
{
case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
break;
}
case CAXMLErrorMessage::ERR_BLOCKED:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_BLOCKED;
break;
}
case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
break;
}
}
}
nextEntry = entry->nextEntry;
entry = nextEntry;
}
}
| void CAAccountingInstance::__commitSettlementToLoginTable | ( | SettleEntry * | entryList | ) | [static] |
only for internal use during the settleTransaction because no login table locks are acquired
Definition at line 3264 of file CAAccountingInstance.cpp.
References SettleEntry::accountNumber, AccountLoginHashEntry::authFlags, SettleEntry::authFlags, AccountLoginHashEntry::authRemoveFlags, SettleEntry::authRemoveFlags, AccountLoginHashEntry::confirmedBytes, SettleEntry::confirmedBytes, Hashtable::getValue(), m_currentAccountsHashtable, ms_pInstance, and SettleEntry::nextEntry.
Referenced by __newSettlementTransaction().
{
SettleEntry *entry = entryList, *nextEntry = NULL;
while (entry != NULL)
{
AccountLoginHashEntry* loginEntry =
(AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
if (loginEntry)
{
// the user is currently logged in
loginEntry->authFlags |= entry->authFlags;
loginEntry->authRemoveFlags |= entry->authRemoveFlags;
if (entry->confirmedBytes > 0 &&
loginEntry->confirmedBytes < entry->confirmedBytes)
{
loginEntry->confirmedBytes = entry->confirmedBytes;
}
}
nextEntry = entry->nextEntry;
entry = nextEntry;
}
}
| SettleEntry * CAAccountingInstance::__handleSettleResult | ( | CAXMLCostConfirmation * | pCC, |
| CAXMLErrorMessage * | pErrMsg, | ||
| CAAccountingDBInterface * | dbInterface, | ||
| UINT64 | a_iSettlementTransactionNr | ||
| ) | [static] |
Definition at line 3024 of file CAAccountingInstance.cpp.
References SettleEntry::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_INVALID_ACCOUNT, AUTH_OUTDATED_CC, AUTH_SETTLED_ONCE, AUTH_UNKNOWN, AUTH_WAITING_FOR_FIRST_SETTLED_CC, SettleEntry::authFlags, SettleEntry::authRemoveFlags, SettleEntry::confirmedBytes, CAAccountingDBInterface::deleteCC(), SettleEntry::diffBytes, E_SUCCESS, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_DATABASE_ERROR, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAXMLErrorMessage::ERR_OK, CAXMLErrorMessage::ERR_OUTDATED_CC, CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS, CAXMLCostConfirmation::getAccountNumber(), CAAccountingDBInterface::getAccountStatus(), CAXMLErrorMessage::getDescription(), CAXMLErrorMessage::getErrorCode(), CAXMLErrorMessage::getMessageObject(), CAXMLCostConfirmation::getTransferredBytes(), m_currentCascade, CAAccountingDBInterface::markAsSettled(), ms_pInstance, print64(), CAMsg::printMsg(), CAAccountingDBInterface::storeAccountStatus(), CAAccountingDBInterface::storeCostConfirmation(), and SettleEntry::storedStatus.
Referenced by __newSettlementTransaction().
{
bool bDeleteCC = false;
UINT32 authFlags = 0;
UINT32 authRemoveFlags = 0;
UINT64 confirmedBytes = 0;
UINT64 diffBytes = 0;
UINT32 storedStatus = 0;
SettleEntry *entry = NULL;
dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
// check returncode
if(pErrMsg == NULL) //no returncode -> connection error
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
}
else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK) //BI reported error
{
CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
pErrMsg->getErrorCode(), pErrMsg->getDescription() );
if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
{
authFlags |= AUTH_INVALID_ACCOUNT;
//dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
bDeleteCC = true;
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
authFlags |= AUTH_ACCOUNT_EMPTY;
UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
if (msgConfirmedBytes)
{
confirmedBytes = *msgConfirmedBytes;
if (confirmedBytes < pCC->getTransferredBytes())
{
diffBytes = pCC->getTransferredBytes() - confirmedBytes;
}
UINT8 tmp[32];
print64(tmp, confirmedBytes);
UINT8 tmp2[32];
print64(tmp2, diffBytes);
UINT8 tmp3[32];
print64(tmp3, pCC->getTransferredBytes());
CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
}
else
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: Account empty, no message object received. User will be kicked out.\n");
}
dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
authFlags |= AUTH_SETTLED_ONCE;
dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
pCC->getTransferredBytes());
//#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
pCC->getTransferredBytes(), pCC->getAccountNumber());
//#endif
}
/*
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
{
// this should never happen; the price certs in this CC do not fit to the ones of the cascade
// bDeleteCC = true;
}*/
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
//get attached CC from error message
CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
if (attachedCC)
{
authFlags |= AUTH_OUTDATED_CC;
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
//store it in DB
if (dbInterface->storeCostConfirmation(*attachedCC,
ms_pInstance->m_currentCascade) == E_SUCCESS)
{
authFlags |= AUTH_SETTLED_ONCE;
if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
attachedCC->getTransferredBytes()) != E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
"Maybe a new CC has been added meanwhile?\n");
}
}
else
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
}
// set the confirmed bytes to the value of the CC got from the PI
confirmedBytes = attachedCC->getTransferredBytes();
}
else
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
}
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
{
authFlags |= AUTH_BLOCKED;
bDeleteCC = true;
dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
{
//authFlags |= AUTH_DATABASE;
// the user is not responsible for this!
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
{
// kick out the user and store the CC
authFlags |= AUTH_UNKNOWN;
}
else
{
// an unknown error leads to user kickout
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
authFlags |= AUTH_UNKNOWN;
bDeleteCC = true;
}
if (bDeleteCC)
{
//delete costconfirmation to avoid trying to settle an unusable CC again and again
if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
}
else
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
}
}
}
else //settling was OK, so mark account as settled
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
authFlags |= AUTH_SETTLED_ONCE;
if (dbInterface->markAsSettled(pCC->getAccountNumber(),
ms_pInstance->m_currentCascade,
pCC->getTransferredBytes()) != E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
}
#ifdef DEBUG
CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: CC OK for account %llu with %llu transferred bytes!\n",
a_iCurrentSettleTransactionNr, pCC->getAccountNumber(), pCC->getTransferredBytes());
#endif
}
if (authFlags || authRemoveFlags)
{
entry = new SettleEntry;
entry->accountNumber = pCC->getAccountNumber();
entry->authFlags = authFlags;
entry->authRemoveFlags = authRemoveFlags;
entry->confirmedBytes = confirmedBytes;
entry->diffBytes = diffBytes;
entry->storedStatus = storedStatus;
}
return entry;
}
| SINT32 CAAccountingInstance::__newSettlementTransaction | ( | UINT32 * | nrOfSettledCCs | ) | [static] |
Definition at line 2774 of file CAAccountingInstance.cpp.
References __commitSettlementToDatabase(), __commitSettlementToLoginTable(), __handleSettleResult(), cleanup(), CRITICAL_SUBSEQUENT_BI_CONN_ERRORS, E_NOT_CONNECTED, E_SUCCESS, E_UNKNOWN, CAAccountingDBInterface::getConnection(), Hashtable::getMutex(), CAAccountingDBInterface::getUnsettledCostConfirmations(), CAAccountingBIInterface::initBIConnection(), CAMutex::lock(), m_currentAccountsHashtable, m_currentCascade, m_iCurrentSettleTransactionNr, m_nextSettleNr, m_pPiInterface, m_pSettlementMutex, m_seqBIConnErrors, m_settleWaitNr, MAX_SETTLED_CCS, MONITORING_FIRE_PAY_EVENT, ms_pInstance, SettleEntry::nextEntry, CAMsg::printMsg(), CAAccountingDBInterface::releaseConnection(), CAAccountingBIInterface::settleAll(), CAConditionVariable::signal(), CAAccountingBIInterface::terminateBIConnection(), CAMutex::unlock(), and CAConditionVariable::wait().
Referenced by newSettlementTransaction().
{
CAXMLErrorMessage **pErrMsgs = NULL, *settleException = NULL;
CAXMLCostConfirmation **allUnsettledCCs = NULL;
SettleEntry *entry = NULL, *nextEntry = NULL;
CAAccountingDBInterface *dbInterface = NULL;
UINT32 nrOfCCs = 0, i = 0;
SINT32 biConnectionStatus = 0, ret = E_SUCCESS;
UINT64 myWaitNr = 0;
//settlement transactions need to be synchronized globally because the settlement thread as well as all login threads
//may start a settlement transaction concurrently.
ms_pInstance->m_pSettlementMutex->lock();
UINT64 iCurrentSettleTransactionNr = (++m_iCurrentSettleTransactionNr) % 50;
dbInterface = CAAccountingDBInterface::getConnection();
if(dbInterface == NULL)
{
ms_pInstance->m_pSettlementMutex->unlock();
CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
ret = E_NOT_CONNECTED;
goto cleanup;
}
/* First part get unsettled CCs from the AI database */
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
#endif
dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
*nrOfSettledCCs = nrOfCCs;
//no unsettled CCs found.
if (allUnsettledCCs == NULL)
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: thread %x looked for unsettled CCs, found no CCs to settle\n", iCurrentSettleTransactionNr, pthread_self());
ms_pInstance->m_pSettlementMutex->unlock();
ret = E_SUCCESS;
goto cleanup;
}
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x looked for unsettled CCs, found %u cost confirmations to settle\n", iCurrentSettleTransactionNr, pthread_self(), nrOfCCs);
//connect to the PI
biConnectionStatus = ms_pInstance->m_pPiInterface->initBIConnection();
if(biConnectionStatus != E_SUCCESS)
{
ms_pInstance->m_seqBIConnErrors++;
if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
{
//transition to critical BI conn payment state
MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
}
else
{
MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
}
ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
ms_pInstance->m_pSettlementMutex->unlock();
CAMsg::printMsg(LOG_WARNING, "Settlement transaction: could not connect to BI. Try later...\n");
//ret = E_SUCCESS;
ret = E_NOT_CONNECTED;
goto cleanup;
}
else
{
pErrMsgs = ms_pInstance->m_pPiInterface->settleAll(allUnsettledCCs, nrOfCCs, &settleException);
ms_pInstance->m_pPiInterface->terminateBIConnection();
}
//workaround because usage of exceptions is not allowed!
if(settleException != NULL)
{
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
ms_pInstance->m_pSettlementMutex->unlock();
CAMsg::printMsg(LOG_ERR, "Settlement transaction: BI reported settlement not successful: "
"code: %i, %s \n", settleException->getErrorCode(),
(settleException->getDescription() != NULL ?
settleException->getDescription() : (UINT8*) "<no description given>") );
ret = E_UNKNOWN;
goto cleanup;
}
if(pErrMsgs == NULL)
{
//this must never happen because in any case where NULL is returned for pErrMsgs
//'settleException' must not be NULL.
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
ms_pInstance->m_pSettlementMutex->unlock();
CAMsg::printMsg(LOG_CRIT, "Settlement transaction: ErrorMessages are null.\n");
ret = E_UNKNOWN;
goto cleanup;
}
else
{
for(i = 0; i < nrOfCCs; i++)
{
nextEntry = __handleSettleResult(allUnsettledCCs[i], pErrMsgs[i], dbInterface, iCurrentSettleTransactionNr);
if(nextEntry != NULL)
{
nextEntry->nextEntry = entry;
entry = nextEntry;
}
}
}
//after settling: apply the corresponding account state changes reported from the PI.
if (entry)
{
//wait numbers are used to obtain a synchronisation with FCFS assertion.
//This additional synchronisation is necessary because before acquiring the login hashtable
//locks the settlementMutex should be released. (Nested locking should be avoided).
if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
{
//CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
//no one is waiting, we use this occasion to reset the wait numbers
ms_pInstance->m_nextSettleNr = 0;
ms_pInstance->m_settleWaitNr = 1;
}
else
{
//get global wait number and wait but release the DBConnection first.
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
myWaitNr = ms_pInstance->m_settleWaitNr;
ms_pInstance->m_settleWaitNr++;
while(myWaitNr != ms_pInstance->m_nextSettleNr)
{
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",
iCurrentSettleTransactionNr, pthread_self(), (myWaitNr - ms_pInstance->m_nextSettleNr));
ms_pInstance->m_pSettlementMutex->wait();
}
CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x may continue (1).\n", iCurrentSettleTransactionNr, pthread_self());
dbInterface = CAAccountingDBInterface::getConnection();
}
bool debugWarn = false;
if (iCurrentSettleTransactionNr != (m_iCurrentSettleTransactionNr % 50))
{
debugWarn = true;
// Write debug message in order to find deadlock...
CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Apply changes to database. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
}
//first apply changes to the database ...
__commitSettlementToDatabase(entry, dbInterface);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
if (debugWarn)
{
// Write debug message in order to find deadlock...
CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Removing settlement mutex lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
}
ms_pInstance->m_pSettlementMutex->unlock();
if (debugWarn)
{
// Write debug message in order to find deadlock...
CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Entering login hashtable. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
}
//... then to the login hashtable after releasing the global settlement lock.
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x with wait nr %llu alters hashtable.\n", iCurrentSettleTransactionNr, pthread_self(), myWaitNr);
__commitSettlementToLoginTable(entry);
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
if (debugWarn)
{
// Write debug message in order to find deadlock...
CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: After commiting to login hashtable, before last lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
}
//indicate that the next thread may proceed with its settlement changes by incrementing the nextSettleNr.
ms_pInstance->m_pSettlementMutex->lock();
ms_pInstance->m_nextSettleNr++;
// TODO: seems to be a bug; if this "if" is set, some locks are never released
//if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
{
//There are threads waiting for applying their settlement results.
if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
CAMsg::printMsg(LOG_INFO, "Thread %x waking up next Thread. %llu are still waiting.\n", pthread_self(),
(ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));
ms_pInstance->m_pSettlementMutex->signal();
}
}
ms_pInstance->m_pSettlementMutex->unlock();
cleanup:
if(dbInterface != NULL)
{
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
if(allUnsettledCCs != NULL)
{
for(i = 0; i < nrOfCCs; i++)
{
delete allUnsettledCCs[i];
allUnsettledCCs[i] = NULL;
}
delete [] allUnsettledCCs;
allUnsettledCCs = NULL;
}
if(pErrMsgs != NULL)
{
for(i = 0; i < nrOfCCs; i++)
{
delete pErrMsgs[i];
pErrMsgs[i] = NULL;
}
pErrMsgs = NULL;
}
while (entry != NULL)
{
nextEntry = entry->nextEntry;
delete entry;
entry = nextEntry;
}
delete settleException;
settleException = NULL;
CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu finished.\n", iCurrentSettleTransactionNr);
return ret;
}
| bool CAAccountingInstance::cascadeMatchesCC | ( | CAXMLCostConfirmation * | pCC | ) | [private] |
Definition at line 843 of file CAAccountingInstance.cpp.
References CAXMLCostConfirmation::getNumberOfHashes(), CAXMLCostConfirmation::getPriceCertHash(), Hashtable::getValue(), m_allHashesLen, m_certHashCC, and CAMsg::printMsg().
Referenced by handleChallengeResponse_internal(), and handleCostConfirmation_internal().
{
UINT8* certHash;
if(m_allHashesLen != pCC->getNumberOfHashes() )
{
return false;
}
for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
{
certHash = pCC->getPriceCertHash(i);
if ((certHash = (UINT8*)m_certHashCC->getValue(certHash)) != NULL)
{
#ifdef DEBUG
CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
#endif
}
else
{
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "CC do not match current cascade.\n");
#endif
return false;
}
}
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "CC matches current Cascade.\n");
#endif
return true;
}
| static SINT32 CAAccountingInstance::clean | ( | ) | [inline, static] |
Definition at line 128 of file CAAccountingInstance.hpp.
References E_SUCCESS, m_preparedCCRequest, MONITORING_FIRE_PAY_EVENT, and ms_pInstance.
{
if(ms_pInstance != NULL)
{
delete ms_pInstance;
ms_pInstance=NULL;
}
if(m_preparedCCRequest != NULL)
{
m_preparedCCRequest->release();
m_preparedCCRequest = NULL;
}
MONITORING_FIRE_PAY_EVENT(ev_pay_aiShutdown);
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::cleanupTableEntry | ( | fmHashTableEntry * | pHashEntry | ) | [static] |
This should always be called when closing a JAP connection to cleanup the data structures.
This should always be called when closing a JAP connection to cleanup the payment data structures and store prepaid bytes.
(pAccInfo->authFlags & AUTH_WAITING_FOR_FIRST_SETTLED_CC))
Definition at line 2559 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_ACCOUNT_OK, AUTH_DELETE_ENTRY, AccountLoginHashEntry::authFlags, t_accountinginfo::authFlags, BEGIN_STACK, t_accountinginfo::clientVersion, AccountLoginHashEntry::confirmedBytes, t_accountinginfo::confirmedBytes, E_SUCCESS, E_UNKNOWN, FINISH_STACK, CAAccountingDBInterface::getConnection(), Hashtable::getMutex(), CALibProxytest::getOptions(), getPrepaidBytes(), CACmdLnOptions::getPrepaidInterval(), Hashtable::getValue(), INIT_STACK, isLoginOngoing(), CAMutex::lock(), m_currentAccountsHashtable, m_currentCascade, ms_pInstance, t_accountinginfo::mutex, t_accountinginfo::nrInQueue, AccountLoginHashEntry::ownerLock, AccountLoginHashEntry::ownerRef, t_fmhashtableentry::pAccountingInfo, t_accountinginfo::pChallenge, t_fmhashtableentry::peerIP, t_accountinginfo::pPublicKey, print64(), CAMsg::printMsg(), t_accountinginfo::pstrBIID, CAAccountingDBInterface::releaseConnection(), Hashtable::remove(), SAVE_STACK, CAAccountingDBInterface::storePrepaidAmount(), testLoginEntryOwner(), and CAMutex::unlock().
Referenced by CAAccountingControlChannel::~CAAccountingControlChannel().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::cleanupTableEntry");
//ms_pInstance->m_pMutex->lock();
tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
AccountLoginHashEntry* loginEntry;
SINT32 prepaidBytes = 0;
SINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
if (pAccInfo == NULL)
{
SAVE_STACK("CAAccountingInstance::cleanupTableEntry", "acc info null");
//ms_pInstance->m_pMutex->unlock();
return E_UNKNOWN;
}
//pAccInfo->mutex->lock();
pHashEntry->pAccountingInfo=NULL;
if (pAccInfo->accountNumber)
{
CAMsg::printMsg(LOG_INFO, "cleaning up entry %p of accountno. %llu (pAccInfo ref: %p)\n",
pHashEntry, pAccInfo->accountNumber, pAccInfo);
if (pAccInfo->authFlags & AUTH_ACCOUNT_OK)
{
// remove login
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
if (loginEntry)
{
// test: delete CC!!!
//ms_pInstance->m_dbInterface->deleteCC(pAccInfo->accountNumber, ms_pInstance->m_currentCascade);
if (testLoginEntryOwner(loginEntry, pHashEntry))// &&
{
if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
{
// make sure to store the correct number of prepaid bytes
pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
}
//store prepaid bytes in database, so the user wont lose the prepaid amount by disconnecting
prepaidBytes = getPrepaidBytes(pAccInfo);
if (prepaidBytes > 0)
{
if (prepaidBytes > prepaidInterval)
{
UINT8 tmp[32];
print64(tmp, pAccInfo->accountNumber);
/* Client paid more than the prepaid interval -
* this is beyond specification and not allowed!
*/
CAMsg::printMsg(LOG_ERR,
"PrepaidBytes of %d for account %s are higher than prepaid interval! "
"The client (owner %x) did not behave according to specification. "
"Deleting prepaid bytes!\n", prepaidBytes, tmp, pHashEntry);
//"Deleting %d bytes...\n", prepaidBytes, tmp, pHashEntry, prepaidBytes - prepaidInterval);
//prepaidBytes = prepaidInterval;
prepaidBytes = 0;
}
}
/*if (ms_pInstance->m_dbInterface)
{
ms_pInstance->m_dbInterface->storePrepaidAmount(pAccInfo->accountNumber,prepaidBytes, ms_pInstance->m_currentCascade);
}*/
CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
if(dbInterface != NULL)
{
dbInterface->storePrepaidAmount(pAccInfo->accountNumber,
prepaidBytes,
ms_pInstance->m_currentCascade);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
if(!isLoginOngoing(loginEntry, pHashEntry))
{
ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
delete loginEntry->ownerLock;
delete loginEntry;
loginEntry = NULL;
}
else
{
CAMsg::printMsg(LOG_INFO, "Cleaning: Leaving loginEntry %x cleanup of owner %x to the next owner due to double-login of a user.\n",
loginEntry, loginEntry->ownerRef);
}
}
/*if (loginEntry->count <= 1)
{
if (loginEntry->count < 1)
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup found non-positive number of user login hash entries (%d)!\n", loginEntry->count);
}
// this is the last active user connection; delete the entry
ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
delete loginEntry->ownerLock;
delete loginEntry;
loginEntry = NULL;
}
else
{
// there are other connections from this user
loginEntry->count--;
}*/
}
else
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup did not find user login hash entry!\n");
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
}
}
else
{
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Cleanup method found account zero.\n");
}
//free memory of pAccInfo
delete pAccInfo->pPublicKey;
pAccInfo->pPublicKey = NULL;
delete [] pAccInfo->pChallenge;
pAccInfo->pChallenge = NULL;
delete [] pAccInfo->pstrBIID;
pAccInfo->pstrBIID = NULL;
delete [] pAccInfo->clientVersion;
pAccInfo->clientVersion = NULL;
pHashEntry->pAccountingInfo=NULL;
if (pAccInfo->nrInQueue > 0)
{
/*
if (pAccInfo->accountNumber == 0)
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for account zero: %u!\n", pAccInfo->nrInQueue);
}
else if (!(pAccInfo->authFlags & AUTH_ACCOUNT_OK))
{
UINT8 accountNrAsString[32];
print64(accountNrAsString, pAccInfo->accountNumber);
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for unauthorized account %s: %u!\n", accountNrAsString, pAccInfo->nrInQueue);
}
else*/
{
// there are still entries in the ai queue; empty it before deletion; we cannot delete it now
pAccInfo->authFlags |= AUTH_DELETE_ENTRY;
}
}
else if (pAccInfo->nrInQueue < 0)
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup method found negative handle queue!\n");
}
//pAccInfo->mutex->unlock();
if (!(pAccInfo->authFlags & AUTH_DELETE_ENTRY))
{
// there are no handles for this entry in the queue, we can savely delete it now
delete pAccInfo->mutex;
pAccInfo->mutex = NULL;
delete [] pAccInfo->clientVersion;
pAccInfo->clientVersion = NULL;
#ifdef LOG_CRIME
UINT64 accountNumber = pAccInfo->accountNumber;
UINT64* surveillanceAccounts = CALibProxytest::getOptions()->getCrimeSurveillanceAccounts();
UINT32 nrOfSurveillanceAccounts = CALibProxytest::getOptions()->getNrOfCrimeSurveillanceAccounts();
const UINT8* peerIP = pHashEntry->peerIP;
for (UINT32 iAccount = 0; iAccount < nrOfSurveillanceAccounts; iAccount++)
{
if (accountNumber == surveillanceAccounts[iAccount])
{
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]);
break;
}
}
#endif
delete pAccInfo;
pAccInfo = NULL;
}
else
{
CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cleanup method sent account deletion request to AI thread!\n");
}
//ms_pInstance->m_pMutex->unlock();
FINISH_STACK("CAAccountingInstance::cleanupTableEntry");
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::finishLoginProcess | ( | fmHashTableEntry * | pHashEntry | ) | [static] |
this method is for the corresponding CAFirstMix login thread to verify the result of the settlement.
Definition at line 1325 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_INVALID_ACCOUNT, AUTH_LOGIN_FAILED, AUTH_LOGIN_NOT_FINISHED, AUTH_LOGIN_SKIP_SETTLEMENT, AUTH_SETTLED_ONCE, AUTH_UNKNOWN, AccountLoginHashEntry::authFlags, t_accountinginfo::authFlags, AccountLoginHashEntry::authRemoveFlags, AccountLoginHashEntry::confirmedBytes, t_accountinginfo::confirmedBytes, CRITICAL_SETTLE_FLAGS, E_SUCCESS, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_NO_BALANCE, CAXMLErrorMessage::ERR_NO_ERROR_GIVEN, CAXMLErrorMessage::ERR_OK, CAAccountingDBInterface::getAccountStatus(), CAAccountingDBInterface::getConnection(), Hashtable::getMutex(), getPrepaidBytes(), Hashtable::getValue(), CAMutex::lock(), m_currentAccountsHashtable, ms_pInstance, t_accountinginfo::mutex, t_fmhashtableentry::pAccountingInfo, t_accountinginfo::pControlChannel, CAMsg::printMsg(), CAAccountingDBInterface::releaseConnection(), sendAILoginConfirmation(), CAAbstractControlChannel::sendXMLMessage(), CAAbstractXMLEncodable::toXmlDocument(), t_accountinginfo::transferredBytes, and CAMutex::unlock().
Referenced by CAFirstMix::doUserLogin_internal().
{
SINT32 ret = 0;
UINT64 accountNumber = 0;
AccountLoginHashEntry *loginEntry;
tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
if(ms_pInstance==NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(ms_pInstance->m_currentAccountsHashtable == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(ms_pInstance->m_currentAccountsHashtable->getMutex() == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(pHashEntry == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(pHashEntry->pAccountingInfo == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(pHashEntry->pAccountingInfo->mutex == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
pAccInfo->mutex->lock();
accountNumber = pAccInfo->accountNumber;
//reset login flags
pAccInfo->authFlags &= (~AUTH_LOGIN_SKIP_SETTLEMENT & ~AUTH_LOGIN_NOT_FINISHED);
if (!(pAccInfo->authFlags & AUTH_SETTLED_ONCE))
{
UINT32 statusCode = 0;
CAAccountingDBInterface* dbInterface = CAAccountingDBInterface::getConnection();
if (dbInterface != NULL && dbInterface->getAccountStatus(accountNumber, statusCode) == E_SUCCESS)
{
if (statusCode > 0)
{
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Using DB status %u.\n",
accountNumber, statusCode);
}
pAccInfo->authFlags |= statusCode;
}
else
{
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Could not fetch status from DB!.\n");
}
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
if (loginEntry)
{
if(loginEntry->authRemoveFlags)
pAccInfo->authFlags &= ~(loginEntry->authRemoveFlags);
pAccInfo->authFlags |= (loginEntry->authFlags & CRITICAL_SETTLE_FLAGS);
}
else
{
pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
}
/*ret = pHashEntry->pAccountingInfo->authFlags &
(AUTH_LOGIN_NOT_FINISHED | AUTH_LOGIN_FAILED);*/
CAXMLErrorMessage *err = NULL;
XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
/* Instead of using special login confirmation messages
* we rather send XMLErrorMessages for backward compatibility reasons
* because old JAPs (version <= 00.09.021) can handle them
*/
if(pAccInfo->authFlags & AUTH_BLOCKED )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED,
(UINT8 *) "AI login: access denied because your account is blocked");
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems blocked.\n", accountNumber);
}
else if(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY,
(UINT8 *) "AI login: access denied because your account is empty");
if ((pAccInfo->authFlags & AUTH_SETTLED_ONCE))
{
pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
{
// this account is really empty; prevent an overflow in the prepaid bytes calculation
pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
}
if (getPrepaidBytes(pAccInfo) > 0)
{
// the user may user his last bytes and is kicked out after that
delete err;
err = NULL;
}
}
else
{
// TODO I am not sure whether this is enough; check this later
loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
}
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems empty.\n", accountNumber);
}
else if(pAccInfo->authFlags & AUTH_INVALID_ACCOUNT )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_BALANCE,
(UINT8 *) "AI login: access denied because your account is not valid");
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems invalid.\n", accountNumber);
}
else if(pAccInfo->authFlags & AUTH_UNKNOWN )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_ERROR_GIVEN,
(UINT8 *) "AI login: error occured while connecting, access denied");
CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Unknown error was found for account %llu.\n", accountNumber);
}
if(err != NULL)
{
err->toXmlDocument(errDoc);
pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
delete err;
err = NULL;
if(errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
ret |= AUTH_LOGIN_FAILED;
}
else
{
//send login confirmation to user, but if the message could not be send, login will fail
/* These login confirmation messages are necessary for the new AI login protocol to indicate
* that the process is finished after a settlement.
* They won't bother old JAPs (version <= 00.09.021) because they will ignore
* these confirmations.
*/
if(sendAILoginConfirmation(pAccInfo,
CAXMLErrorMessage::ERR_OK,
(UINT8*) "AI login successful") != E_SUCCESS)
{
ret |= AUTH_LOGIN_FAILED;
}
}
/* unlock the loginEntry object for other login threads */
//resetLoginOngoing(loginEntry, pHashEntry);
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
pAccInfo->mutex->unlock();
return ret;
}
| UINT32 CAAccountingInstance::getAuthFlags | ( | fmHashTableEntry * | pHashEntry | ) | [static] |
Definition at line 226 of file CAAccountingInstance.cpp.
References t_accountinginfo::authFlags, and t_fmhashtableentry::pAccountingInfo.
Referenced by CAFirstMixA::checkUserConnections().
{
if (pHashEntry == NULL)
{
return 0;
}
tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
if (pAccInfo == NULL)
{
return 0;
}
return pAccInfo->authFlags;
}
| UINT32 CAAccountingInstance::getNrOfUsers | ( | ) | [static] |
Definition at line 243 of file CAAccountingInstance.cpp.
References Hashtable::getSize(), CAMutex::lock(), m_currentAccountsHashtable, m_pMutex, ms_pInstance, CAMsg::printMsg(), and CAMutex::unlock().
{
UINT32 users = 0;
if (ms_pInstance != NULL)
{
ms_pInstance->m_pMutex->lock();
if(ms_pInstance->m_currentAccountsHashtable != NULL)
{
// getting the size is an atomic operation and does not need synchronization
users = ms_pInstance->m_currentAccountsHashtable->getSize();
}
else
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Trying to access Hashtable after it has been disposed!!.\n");
}
ms_pInstance->m_pMutex->unlock();
}
return users;
}
| SINT32 CAAccountingInstance::getPrepaidBytes | ( | tAiAccountingInfo * | pAccInfos | ) | [static, private] |
Definition at line 661 of file CAAccountingInstance.cpp.
References t_accountinginfo::confirmedBytes, CAMsg::printMsg(), and t_accountinginfo::transferredBytes.
Referenced by cleanupTableEntry(), finishLoginProcess(), handleCostConfirmation_internal(), handleJapPacket_internal(), and processJapMessage().
{
if (pAccInfo == NULL)
{
return 0;
}
//most unlikely that either transferred bytes or confirmed bytes
//are > 0x8000000000000000
SINT64 prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
//difference must be a value that fits into a signed 32 bit integer.
if ((prepaidBytes > 0) && (prepaidBytes & 0x7FFFFFFF00000000LL))
{
CAMsg::printMsg(LOG_CRIT, "PrepaidBytes overflow: %lld\n", prepaidBytes);
CAMsg::printMsg(LOG_INFO, "TransferredBytes: %llu ConfirmedBytes: %llu\n", pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
}
return (SINT32) prepaidBytes;
/*SINT32 prepaidBytes;
#ifdef DEBUG
CAMsg::printMsg(LOG_INFO, "Calculating TransferredBytes: %llu ConfirmedBytes: %llu\n",
pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
#endif
if (pAccInfo->confirmedBytes > pAccInfo->transferredBytes)
{
prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
if (prepaidBytes < 0)
{
// PrepaidBytes should be greater than 0 !!!
UINT8 tmp[32], tmp2[32];
print64(tmp,pAccInfo->transferredBytes);
print64(tmp2,pAccInfo->confirmedBytes);
CAMsg::printMsg(LOG_CRIT, "PrepaidBytes are way to high! Maybe a hacker attack? Or CC did get lost?\n");
CAMsg::printMsg(LOG_INFO, "TransferredBytes: %s ConfirmedBytes: %s\n", tmp, tmp2);
UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
prepaidBytes = (SINT32)prepaidInterval;
pAccInfo->transferredBytes = pAccInfo->confirmedBytes - prepaidInterval;
}
}
else
{
prepaidBytes = pAccInfo->transferredBytes - pAccInfo->confirmedBytes;
prepaidBytes *= -1;
}
return prepaidBytes;*/
}
| UINT32 CAAccountingInstance::handleAccountCertificate | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Handles an account certificate of a newly connected Jap.
Definition at line 1489 of file CAAccountingInstance.cpp.
References FINISH_STACK, handleAccountCertificate_internal(), and INIT_STACK.
Referenced by processJapMessage().
{
return handleAccountCertificate_internal(pAccInfo, root);
INIT_STACK;
FINISH_STACK("CAAccountingInstance::handleAccountCertificate");
}
| UINT32 CAAccountingInstance::handleAccountCertificate_internal | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Handles an account certificate of a newly connected Jap.
Parses accountnumber and publickey, checks the signature and generates and sends a challenge XML structure to the Jap. TODO: think about switching account without changing mixcascade (receive a new acc.cert. though we already have one)
Definition at line 1506 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_CHALLENGE_SENT, AUTH_DELETE_ENTRY, AUTH_FAKE, AUTH_GOT_ACCOUNTCERT, AUTH_TIMEOUT_STARTED, t_accountinginfo::authFlags, BEGIN_STACK, t_accountinginfo::challengeSentSeconds, createDOMDocument(), createDOMElement(), DOM_Output::dumpToMem(), E_SUCCESS, CABase64::encode(), CAXMLErrorMessage::ERR_BAD_REQUEST, CAXMLErrorMessage::ERR_BAD_SIGNATURE, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAXMLErrorMessage::ERR_NO_ERROR_GIVEN, CAXMLErrorMessage::ERR_NO_RECORD_FOUND, CAXMLErrorMessage::ERR_OK, CAXMLErrorMessage::ERR_WRONG_FORMAT, CAAccountingDBInterface::getConnection(), getcurrentTime(), getDOMChildByName(), getDOMElementValue(), CALibProxytest::getOptions(), CAAccountingDBInterface::getPrepaidAmount(), getRandom(), INIT_STACK, len, CAMutex::lock(), m_currentCascade, t_accountinginfo::mutex, t_accountinginfo::pChallenge, t_accountinginfo::pControlChannel, t_accountinginfo::pPublicKey, CAMsg::printMsg(), t_accountinginfo::pstrBIID, CAAccountingDBInterface::releaseConnection(), CAAbstractControlChannel::sendXMLMessage(), setDOMElementAttribute(), setDOMElementValue(), CASignature::setVerifyKey(), CAAbstractXMLEncodable::toXmlDocument(), CAMutex::unlock(), and CAMultiSignature::verifyXML().
Referenced by handleAccountCertificate().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::handleAccountCertificate");
//CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate start\n");
//CAMsg::printMsg(LOG_DEBUG, "started method handleAccountCertificate\n");
DOMElement* elGeneral=NULL;
timespec now;
getcurrentTime(now);
// check authstate of this user
if (pAccInfo == NULL)
{
return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
}
pAccInfo->mutex->lock();
if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
{
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
}
if (pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)
{
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Already got an account cert. Ignoring...");
#endif
CAXMLErrorMessage err(
CAXMLErrorMessage::ERR_BAD_REQUEST,
(UINT8*)"You have already sent an Account Certificate"
);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_BAD_REQUEST;
}
// parse & set accountnumber
if (getDOMChildByName( root, "AccountNumber", elGeneral, false ) != E_SUCCESS ||
getDOMElementValue( elGeneral, pAccInfo->accountNumber ) != E_SUCCESS)
{
CAMsg::printMsg( LOG_ERR, "AccountCertificate has wrong or no accountnumber. Ignoring...\n");
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_FORMAT);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_FORMAT;
}
// parse & set payment instance id
UINT32 len=256;
pAccInfo->pstrBIID=new UINT8[256];
if ( getDOMChildByName( root,"BiID", elGeneral, false ) != E_SUCCESS ||
getDOMElementValue( elGeneral,pAccInfo->pstrBIID, &len ) != E_SUCCESS)
{
delete[] pAccInfo->pstrBIID;
pAccInfo->pstrBIID = NULL;
CAMsg::printMsg( LOG_ERR, "AccountCertificate has no Payment Instance ID. Ignoring...\n");
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_FORMAT);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_FORMAT;
}
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Stored payment instance ID: %s\n", pAccInfo->pstrBIID);
#endif
// parse & set public key
if ( getDOMChildByName( root, "JapPublicKey", elGeneral, false ) != E_SUCCESS )
{
CAMsg::printMsg( LOG_ERR, "AccountCertificate contains no public key. Ignoring...\n");
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_KEY_NOT_FOUND;
}
#ifdef DEBUG
UINT8* aij;
UINT32 aijsize;
aij = DOM_Output::dumpToMem(elGeneral, &aijsize);
aij[aijsize-1]=0;
CAMsg::printMsg( LOG_DEBUG, "Setting user public key %s>\n", aij );
delete[] aij;
aij = NULL;
#endif
pAccInfo->pPublicKey = new CASignature();
if ( pAccInfo->pPublicKey->setVerifyKey( elGeneral ) != E_SUCCESS )
{
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
}
//if ((!m_pJpiVerifyingInstance) ||
//(m_pJpiVerifyingInstance->verifyXML( root, (CACertStore *)NULL ) != E_SUCCESS ))
if(CAMultiSignature::verifyXML(root, CALibProxytest::getOptions()->getBI()->getCertificate()))
{
// signature invalid. mark this user as bad guy
CAMsg::printMsg( LOG_INFO, "CAAccountingInstance::handleAccountCertificate(): Bad Jpi signature\n" );
pAccInfo->authFlags |= AUTH_FAKE | AUTH_GOT_ACCOUNTCERT | AUTH_TIMEOUT_STARTED;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
}
UINT8 * arbChallenge;
UINT8 b64Challenge[ 512 ];
UINT32 b64Len = 512;
//CAMsg::printMsg(LOG_DEBUG, "Almost finished handleAccountCertificate, preparing challenge\n");
// generate random challenge data and Base64 encode it
arbChallenge = new UINT8[222];
getRandom( arbChallenge, 222 );
CABase64::encode( arbChallenge, 222, b64Challenge, &b64Len );
delete[] pAccInfo->pChallenge;
pAccInfo->pChallenge = arbChallenge; // store challenge for later..
// generate XML challenge structure
XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
DOMElement* elemRoot = createDOMElement(doc, "Challenge" );
DOMElement* elemPanic = createDOMElement(doc, "DontPanic" );
DOMElement* elemPrepaid = createDOMElement(doc, "PrepaidBytes" );
setDOMElementAttribute(elemPanic, "version",(UINT8*) "1.0" );
doc->appendChild( elemRoot );
elemRoot->appendChild( elemPanic );
elemRoot->appendChild( elemPrepaid );
setDOMElementValue( elemPanic, b64Challenge );
SINT32 prepaidAmount = 0; //m_dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
//TODO: this is not a good moment to send the prepaid-bytes to the JonDo.
//we cannot be sure that the database contains a consistent value here.
if(dbInterface != NULL)
{
prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
SINT32 prepaidIvalLowerBound = 0; //(-1*(SINT32)CALibProxytest::getOptions()->getPrepaidInterval()); /* EXPERIMENTAL: transmit negative prepaid bytes (but not less than -PREPAID_BYTES) */
if (prepaidAmount < prepaidIvalLowerBound)
{
prepaidAmount = prepaidIvalLowerBound;
}
//CAMsg::printMsg( LOG_DEBUG, "handleAccountCertificate read %i prepaid bytes\n", prepaidAmount);
setDOMElementValue( elemPrepaid, prepaidAmount);
// send XML struct to Jap & set auth flags
pAccInfo->pControlChannel->sendXMLMessage(doc);
if (doc != NULL)
{
doc->release();
doc = NULL;
}
pAccInfo->authFlags |= AUTH_CHALLENGE_SENT | AUTH_GOT_ACCOUNTCERT | AUTH_TIMEOUT_STARTED;
pAccInfo->challengeSentSeconds = time(NULL);
//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]);
//CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate stop\n");
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_OK;
}
| UINT32 CAAccountingInstance::handleChallengeResponse | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Checks the response of the challenge-response auth.
Definition at line 1715 of file CAAccountingInstance.cpp.
References FINISH_STACK, handleChallengeResponse_internal(), and INIT_STACK.
Referenced by processJapMessage().
{
return handleChallengeResponse_internal(pAccInfo, root);
INIT_STACK;
FINISH_STACK("CAAccountingInstance::handleChallengeResponse");
}
| UINT32 CAAccountingInstance::handleChallengeResponse_internal | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Handles the response to our challenge.
Checks the validity of the response and sets the user's authFlags Also gets the last CC of the user, and sends it to the JAP accordingly.
Definition at line 1729 of file CAAccountingInstance.cpp.
References AccountLoginHashEntry::accountNumber, t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_ACCOUNT_OK, AUTH_BLOCKED, AUTH_CHALLENGE_SENT, AUTH_DELETE_ENTRY, AUTH_FAKE, AUTH_GOT_ACCOUNTCERT, AUTH_INVALID_ACCOUNT, AUTH_MULTIPLE_LOGIN, AUTH_WAITING_FOR_FIRST_SETTLED_CC, AccountLoginHashEntry::authFlags, t_accountinginfo::authFlags, AccountLoginHashEntry::authRemoveFlags, BEGIN_STACK, t_accountinginfo::bytesToConfirm, cascadeMatchesCC(), t_fmhashtableentry::cleanupNotifier, CLIENT_VERSION_STR_LEN, t_accountinginfo::clientVersion, AccountLoginHashEntry::confirmedBytes, t_accountinginfo::confirmedBytes, AccountLoginHashEntry::count, CABase64::decode(), E_SUCCESS, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BAD_SIGNATURE, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, CAXMLErrorMessage::ERR_NO_ERROR_GIVEN, CAXMLErrorMessage::ERR_NO_RECORD_FOUND, CAXMLErrorMessage::ERR_OK, CAXMLErrorMessage::ERR_WRONG_FORMAT, CAFirstMix::forceKickout(), CAAccountingDBInterface::getAccountStatus(), CAAccountingDBInterface::getConnection(), CAAccountingDBInterface::getCostConfirmation(), getDOMChildByName(), getDOMElementValue(), CAFirstMix::getLoginMutex(), Hashtable::getMutex(), CALibProxytest::getOptions(), CAAccountingDBInterface::getPrepaidAmount(), CACmdLnOptions::getPrepaidInterval(), CAXMLCostConfirmation::getTransferredBytes(), Hashtable::getValue(), CAXMLCostConfirmation::getXMLDocument(), INIT_STACK, CAMutex::lock(), AccountLoginHashEntry::loginOngoing, m_currentAccountsHashtable, m_currentCascade, m_mix, ms_pInstance, t_accountinginfo::mutex, AccountLoginHashEntry::ownerLock, AccountLoginHashEntry::ownerRef, t_accountinginfo::ownerRef, t_accountinginfo::pChallenge, t_accountinginfo::pControlChannel, t_accountinginfo::pPublicKey, PREPAID_PROTO_CLIENT_VERSION, print64(), CAMsg::printMsg(), Hashtable::put(), CAAccountingDBInterface::releaseConnection(), Hashtable::remove(), sendCCRequest(), sendInitialCCRequest(), CAAbstractControlChannel::sendXMLMessage(), testAndSetLoginOwner(), CAAbstractXMLEncodable::toXmlDocument(), t_accountinginfo::transferredBytes, CAMutex::unlock(), AccountLoginHashEntry::userID, t_accountinginfo::userID, CASignature::verifyDER(), and CAConditionVariable::wait().
Referenced by handleChallengeResponse().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::handleChallengeResponse");
//CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse start\n");
UINT8 decodeBuffer[ 512 ];
UINT32 decodeBufferLen = 512;
UINT32 usedLen;
/* DOMElement* elemPanic=NULL;
DSA_SIG * pDsaSig=NULL; */
SINT32 prepaidAmount = 0;
AccountLoginHashEntry* loginEntry;
CAXMLCostConfirmation* pCC = NULL;
bool bSendCCRequest = true;
UINT32 status;
// check current authstate
if (pAccInfo == NULL)
{
return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
}
pAccInfo->mutex->lock();
if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
{
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
}
if( (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)) ||
(!(pAccInfo->authFlags & AUTH_CHALLENGE_SENT))
)
{
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
}
pAccInfo->authFlags &= ~AUTH_CHALLENGE_SENT;
// get raw bytes of response
if ( getDOMElementValue( root, decodeBuffer, &decodeBufferLen ) != E_SUCCESS )
{
CAMsg::printMsg( LOG_DEBUG, "ChallengeResponse has wrong XML format. Ignoring\n" );
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_FORMAT;
}
DOMElement *elemClientVersion = NULL;
getDOMChildByName(root, "ClientVersion", elemClientVersion, false);
if(elemClientVersion != NULL)
{
UINT32 clientVersionStrLen = CLIENT_VERSION_STR_LEN;
UINT8 *clientVersionStr = new UINT8[clientVersionStrLen];
memset(clientVersionStr, 0, clientVersionStrLen);
if( getDOMElementValue(elemClientVersion, clientVersionStr, &clientVersionStrLen) != E_SUCCESS)
{
delete [] clientVersionStr;
clientVersionStr = NULL;
}
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Client Version (account %llu): %s\n",
pAccInfo->accountNumber,
(clientVersionStr != NULL ? clientVersionStr : (UINT8*) "<not set>"));
#endif
pAccInfo->clientVersion = clientVersionStr;
}
else
{
pAccInfo->clientVersion = NULL;
}
decodeBuffer[decodeBufferLen] = 0;
usedLen = decodeBufferLen;
decodeBufferLen = 512;
CABase64::decode( decodeBuffer, usedLen, decodeBuffer, &decodeBufferLen );
/*
UINT8 b64Challenge[ 512 ];
UINT32 b64Len = 512;
CABase64::encode(pHashEntry->pAccountingInfo->pChallenge, 222, b64Challenge, &b64Len);
CAMsg::printMsg(LOG_DEBUG, "Challenge:\n%s\n", b64Challenge);
*/
// check signature
//pDsaSig = DSA_SIG_new();
CASignature * sigTester = pAccInfo->pPublicKey;
//sigTester->decodeRS( decodeBuffer, decodeBufferLen, pDsaSig );
if ( sigTester->verifyDER( pAccInfo->pChallenge, 222, decodeBuffer, decodeBufferLen )
!= E_SUCCESS )
{
UINT8 accountNrAsString[32];
print64(accountNrAsString, pAccInfo->accountNumber);
CAMsg::printMsg(LOG_ERR, "Challenge-response authentication failed for account %s!\n", accountNrAsString);
pAccInfo->authFlags |= AUTH_FAKE;
pAccInfo->authFlags &= ~AUTH_ACCOUNT_OK;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
}
pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
//EXPERIMENTAL NEW CODE for intercepting multiple login attempts
m_currentAccountsHashtable->getMutex()->lock();
loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
struct t_fmhashtableentry *ownerRef = NULL;
if(loginEntry != NULL) // (other) user (with same account) already logged in
{
ownerRef = loginEntry->ownerRef;
if(ownerRef != NULL)
{
bool isLoginFree = testAndSetLoginOwner(loginEntry, ownerRef);
//obtaining ownership and setting loginProcessOngoing also means to cleanup the
//old login entry after the connection belonging to the old login is closed.
//So it can be assured that no other login-thread will find a NULL entry at the above if-statement
m_currentAccountsHashtable->getMutex()->unlock();
//abort if another thread is logging in but ...
if(!isLoginFree)
{
CAMsg::printMsg(LOG_DEBUG, "Exiting because login is occupied for owner %p of account %llu.\n", ownerRef);
pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
}
//...if the former login is finished and the connection is in use: force the previous login-connection to be kicked out.
m_mix->getLoginMutex()->lock();
CAXMLErrorMessage kickoutMsg(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN);
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
kickoutMsg.toXmlDocument(errDoc);
//Note: the ownerRef hashEntry can already be cleared at that point.
if( m_mix->forceKickout(ownerRef, errDoc) )
{
CAMsg::printMsg(LOG_DEBUG, "Kickout was requested for owner %p of account %llu, waiting...\n", ownerRef,
pAccInfo->accountNumber);
//Synchronize until the main thread can sure that the connection is closed. (After FirstMixA::checkConnections()
// in main loop)
//not dangerous if ensured that the cleanup notifier is always locked after loginCV
//but it is necessary to lock cleanupNotifier before releasing loginCV. otherwise we might lose
//the signal from cleanupNotifier. This can't happen if the main thread that
//peforms the cleanup is still blokced by loginCV before it can acquire cleanupNotifier during the cleanup.
ownerRef->cleanupNotifier->lock();
m_mix->getLoginMutex()->unlock();
ownerRef->cleanupNotifier->wait();
ownerRef->cleanupNotifier->unlock();
}
else
{
m_mix->getLoginMutex()->unlock();
//if the forceKickout returns false the ownerRef was already cleared.
//no need to wait any further.
CAMsg::printMsg(LOG_INFO, "ownerRef %p of account %llu already kicked out.\n", ownerRef, pAccInfo->accountNumber);
}
errDoc->release();
errDoc = NULL;
//obtain hashtable lock again.
m_currentAccountsHashtable->getMutex()->lock();
if(loginEntry != NULL)
{
//When login ownership was obtained: cleanup the former entry.
CAMsg::printMsg(LOG_INFO, "finally cleaning up loginEntry %p for former owner %p of account %llu\n",
loginEntry, loginEntry->ownerRef, pAccInfo->accountNumber);
ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
delete loginEntry->ownerLock;
delete loginEntry;
loginEntry = NULL;
}
}
else
{
//Impossible or Bug
CAMsg::printMsg(LOG_CRIT, "BUG: ownerRef of an active login entry MUST NOT be null. Please report.\n");
m_currentAccountsHashtable->getMutex()->unlock();
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
}
}
//POST CONDITION: old login entry cleared.
loginEntry = new AccountLoginHashEntry;
loginEntry->accountNumber = pAccInfo->accountNumber;
loginEntry->count = 1;
loginEntry->confirmedBytes = 0;
loginEntry->authRemoveFlags = 0;
loginEntry->authFlags = 0;
loginEntry->userID = pAccInfo->userID;
loginEntry->ownerRef = pAccInfo->ownerRef;
loginEntry->loginOngoing = true;
loginEntry->ownerLock = new CAMutex();
m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
//m_currentAccountsHashtable->getMutex()->unlock();
// fetch cost confirmation from last session if available, and retrieve information; synchronized with settle thread
bool bSettled;
CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Checking database for previously prepaid bytes...\n");
#endif
if(dbInterface != NULL)
{
prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC, bSettled);
}
else
{
prepaidAmount = 0;
}
if (pCC != NULL)
{
if(!cascadeMatchesCC(pCC))
{
delete pCC;
pCC = NULL;
CAMsg::printMsg(LOG_INFO, "CC do not match current Cascade. Discarding CC.\n");
}
}
if (pCC != NULL)
{
if (bSettled)
{
pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
}
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "pAccInfo->transferredBytes is %llu, confirmedBytes: %llu, pCC->transferredBytes is %llu\n",
pAccInfo->transferredBytes, pAccInfo->confirmedBytes, pCC->getTransferredBytes());
#endif
pAccInfo->transferredBytes += pCC->getTransferredBytes();
pAccInfo->confirmedBytes = pCC->getTransferredBytes();
#ifdef DEBUG
UINT8 tmp[32];
print64(tmp,pAccInfo->transferredBytes);
CAMsg::printMsg(LOG_DEBUG, "Setting confirmedBytes to %llu, pAccInfo->transferredBytes is now %s\n",
pAccInfo->confirmedBytes, tmp);
#endif
//delete pCC;
}
else
{
UINT8 tmp[32];
print64(tmp,pAccInfo->accountNumber);
CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cost confirmation for account %s not found in database. This seems to be a new user.\n", tmp);
}
//pAccInfo->mutex->unlock();
// m_currentAccountsHashtable->getMutex()->lock();
// pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
//
// loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
// //now loginEntry == NULL must be asserted
// if (!loginEntry)
// {
// // remember that this user is logged in at least once
// loginEntry = new AccountLoginHashEntry;
// loginEntry->accountNumber = pAccInfo->accountNumber;
// loginEntry->count = 1;
// loginEntry->confirmedBytes = 0;
// loginEntry->authRemoveFlags = 0;
// loginEntry->authFlags = 0;
// loginEntry->userID = pAccInfo->userID;
// m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
// if (!(AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber)))
// {
// UINT8 accountNrAsString[32];
// print64(accountNrAsString, pAccInfo->accountNumber);
// CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Could not insert login entry for account %s!", accountNrAsString);
// }
// }
// else
// {
// loginEntry->count++;
// }
// if (loginEntry->count > 1)
// {
// /*
// * There already is a user logged in with this account.
// */
// UINT8 accountNrAsString[32];
// print64(accountNrAsString, pAccInfo->accountNumber);
// if (loginEntry->count < MAX_TOLERATED_MULTIPLE_LOGINS)
// {
// // There is now more than one user logged in with this account; kick out the other users!
// CAMsg::printMsg(LOG_INFO,
// "CAAccountingInstance: Multiple logins (%d) of user with account %s detected! Kicking out other users with this account...\n",
// loginEntry->count, accountNrAsString);
// loginEntry->userID = pAccInfo->userID; // this is the current user; kick out the others
// }
// else
// {
// /* The maximum of tolerated concurrent logins for this user is exceeded.
// * He won't get any new access again before the old connections have been closed!
// * @mod: in this case not more than one login is allowed at a time. The User has to wait until
// * the old login will be deleted.
// */
// CAMsg::printMsg(LOG_INFO,
// "CAAccountingInstance: Maximum of multiple logins exceeded (%d) for user with account %s! Kicking out this user!\n",
// loginEntry->count, accountNrAsString);
// bSendCCRequest = false; // not needed...
// pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
//
// delete pCC;
// pCC = NULL;
// m_currentAccountsHashtable->getMutex()->unlock();
// pAccInfo->mutex->unlock();
// return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
// }
// }
UINT8 tmp[32];
print64(tmp,pAccInfo->accountNumber);
if (prepaidAmount > 0)
{
CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Got %d prepaid bytes for account nr. %s.\n",prepaidAmount, tmp);
//pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
if (pAccInfo->transferredBytes >= (UINT32)prepaidAmount)
{
pAccInfo->transferredBytes -= prepaidAmount;
}
else
{
UINT8 tmp2[32];
print64(tmp2, pAccInfo->transferredBytes);
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Transferred bytes of %s for account %s are lower than prepaid amount! "
"Maybe we lost a CC?\n",tmp2, tmp);
prepaidAmount = 0;
}
}
else
{
prepaidAmount = 0;
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: No database record for prepaid bytes found for account nr. %s.\n", tmp);
}
//CAMsg::printMsg(LOG_DEBUG, "Number of prepaid (confirmed-transferred) bytes : %d \n",pAccInfo->confirmedBytes-pAccInfo->transferredBytes);
SINT32 dbRet;
if(dbInterface != NULL);
{
dbRet = dbInterface->getAccountStatus(pAccInfo->accountNumber, status);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
if (dbRet != E_SUCCESS)
{
UINT8 tmp[32];
print64(tmp,pAccInfo->accountNumber);
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Could not check status for account %s!\n", tmp);
}
else if (status > CAXMLErrorMessage::ERR_OK)
{
//UINT32 authFlags = 0;
//the auth flags are set after this check, but they need to be verified during a forced settlement
//at the end of the login. (see finishLoginProcess())
CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Illegal status %u for account %llu found.\n",
status, pAccInfo->accountNumber);
if (status == CAXMLErrorMessage::ERR_BLOCKED)
{
pAccInfo->authFlags |= AUTH_BLOCKED;
}
else if (status == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
{
pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
}
else if (status == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
{
pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
}
/*if (authFlags)
{
pAccInfo->authFlags |= AUTH_BLOCKED;
if (loginEntry->confirmedBytes == 0)
{
loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
}
}*/
}
m_currentAccountsHashtable->getMutex()->unlock();
//pAccInfo->mutex->lock();
SINT32 sendStatus = E_SUCCESS;
if (bSendCCRequest)
{
// fetch cost confirmation from last session if available, and send it
//CAXMLCostConfirmation * pCC = NULL;
//m_dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC);
if(pCC != NULL)
{
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Sending pcc to sign with %llu transferred bytes\n", pCC->getTransferredBytes());
#endif
// the typical case; the user had logged in before
/* there shouldn't be any counting synchronisation problems with the JAP
* because the new login protocol doesn't permit JAPs
* to exchange data before login is finished.
*/
UINT32 prepaidIval = CALibProxytest::getOptions()->getPrepaidInterval();
pAccInfo->bytesToConfirm = (prepaidIval - prepaidAmount) + pCC->getTransferredBytes();
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before CC request, bytesToConfirm: %llu, prepaidIval: %u, "
"prepaidAmount: %d, transferred bytes: %llu\n",
pAccInfo->bytesToConfirm, prepaidIval, prepaidAmount, pAccInfo->transferredBytes);
#endif
if( (pAccInfo->clientVersion == NULL) ||
(strncmp((char*)pAccInfo->clientVersion, PREPAID_PROTO_CLIENT_VERSION, CLIENT_VERSION_STR_LEN) < 0) )
{
//old CC without payRequest and prepaid bytes.
//CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: Old prepaid proto version.\n", pAccInfo->accountNumber);
sendStatus = pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
}
else
{
//CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: New prepaid proto version. prepaid bytes: %d\n",
// pAccInfo->accountNumber, prepaidAmount);
sendStatus = sendInitialCCRequest(pAccInfo, pCC, prepaidAmount);
}
}
else
{
// there is no CC in the database; typically this is the first connection of this user
if (prepaidAmount > 0)
{
// Delete any previously stored prepaid amount; there should not be any! CC lost?
pAccInfo->transferredBytes += prepaidAmount;
}
sendStatus = sendCCRequest(pAccInfo);
}
}
delete pCC;
pCC = NULL;
if ( pAccInfo->pChallenge != NULL ) // free mem
{
delete[] pAccInfo->pChallenge;
pAccInfo->pChallenge = NULL;
}
//CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse stop\n");
pAccInfo->mutex->unlock();
if(sendStatus == E_SUCCESS)
{
return CAXMLErrorMessage::ERR_OK;
}
else
{
return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
}
}
| UINT32 CAAccountingInstance::handleCostConfirmation | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Handles a cost confirmation sent by a jap.
Definition at line 2197 of file CAAccountingInstance.cpp.
References FINISH_STACK, handleCostConfirmation_internal(), and INIT_STACK.
Referenced by processJapMessage().
{
return handleCostConfirmation_internal(pAccInfo, root);
INIT_STACK;
FINISH_STACK("CAAccountingInstance::handleCostConfirmation");
}
| UINT32 CAAccountingInstance::handleCostConfirmation_internal | ( | tAiAccountingInfo * | pAccInfo, |
| DOMElement * | root | ||
| ) | [private] |
Handles a cost confirmation sent by a jap.
Definition at line 2207 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_ACCOUNT_OK, AUTH_DATABASE, AUTH_DELETE_ENTRY, AUTH_FAKE, AUTH_GOT_ACCOUNTCERT, AUTH_HARD_LIMIT_REACHED, AUTH_LOGIN_NOT_FINISHED, AUTH_LOGIN_SKIP_SETTLEMENT, AUTH_SENT_CC_REQUEST, AUTH_WAITING_FOR_FIRST_SETTLED_CC, t_accountinginfo::authFlags, BEGIN_STACK, t_accountinginfo::bytesToConfirm, cascadeMatchesCC(), t_accountinginfo::confirmedBytes, E_SUCCESS, E_UNKNOWN, CAXMLErrorMessage::ERR_BAD_REQUEST, CAXMLErrorMessage::ERR_BAD_SIGNATURE, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_NO_ERROR_GIVEN, CAXMLErrorMessage::ERR_NO_RECORD_FOUND, CAXMLErrorMessage::ERR_OK, CAXMLErrorMessage::ERR_WRONG_DATA, CAXMLErrorMessage::ERR_WRONG_FORMAT, CAXMLCostConfirmation::getAccountNumber(), CAAccountingDBInterface::getConnection(), getcurrentTimeMillis(), CAXMLCostConfirmation::getInstance(), CAXMLCostConfirmation::getNumberOfHashes(), CALibProxytest::getOptions(), getPrepaidBytes(), CACmdLnOptions::getPrepaidInterval(), CAXMLCostConfirmation::getTransferredBytes(), INIT_STACK, t_accountinginfo::lastHardLimitSeconds, CAMutex::lock(), m_allHashesLen, m_currentCascade, m_pSettleThread, t_accountinginfo::mutex, t_accountinginfo::pControlChannel, t_accountinginfo::pPublicKey, print64(), CAMsg::printMsg(), CAAccountingDBInterface::releaseConnection(), CAAbstractControlChannel::sendXMLMessage(), CAAccountingSettleThread::settle(), CAAccountingDBInterface::storeCostConfirmation(), CAAbstractXMLEncodable::toXmlDocument(), t_accountinginfo::transferredBytes, CAMutex::unlock(), and CASignature::verifyXML().
Referenced by handleCostConfirmation().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::handleCostConfirmation");
if (pAccInfo == NULL)
{
return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
}
pAccInfo->mutex->lock();
if ( (pAccInfo->authFlags & AUTH_DELETE_ENTRY) ||
(!(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED ) && (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )) )
{
CAMsg::printMsg(LOG_ERR,
"CAAccountingInstance::handleCostConfirmation Ignoring CC, restricted flags set: %s %s\n",
((pAccInfo->authFlags & AUTH_DELETE_ENTRY) ? "AUTH_DELETE_ENTRY" : "") ,
((pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY) ? "AUTH_ACCOUNT_EMPTY" : ""));
// ignore CCs for this account!
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
}
// check authstate
if (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
!(pAccInfo->authFlags & AUTH_ACCOUNT_OK) ||
!(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST))
{
CAMsg::printMsg(LOG_ERR,
"CAAccountingInstance::handleCostConfirmation CC was received but has not been requested! Ignoring...\n");
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
}
CAXMLCostConfirmation* pCC = CAXMLCostConfirmation::getInstance(root);
if(pCC==NULL)
{
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
}
// for debugging only: test signature the oldschool way
// warning this removes the signature from doc!!!
if (pAccInfo->pPublicKey==NULL||
pAccInfo->pPublicKey->verifyXML( root ) != E_SUCCESS)
{
// wrong signature
CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
}
#ifdef DEBUG
else
{
CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
}
#endif
if (pCC->getNumberOfHashes() != m_allHashesLen)
{
CAMsg::printMsg( LOG_INFO, "CostConfirmation has illegal number of price cert hashes!\n" );
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
(UINT8*)"CostConfirmation has illegal number of price cert hashes");
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_FORMAT;
}
/*Hashtable* certHashCC =
new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
UINT8* certHash;*/
//bool bFailed = false;
//for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
//{
// certHash = pCC->getPriceCertHash(i);
// certHashCC->put(certHash, certHash);
/*
if ((certHash = (UINT8*)certHashCC->getValue(certHash)) != NULL)
{
CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
}*/
//}
//for (UINT32 i = 0; i < m_allHashesLen; i++)
//{
//CAMsg::printMsg( LOG_INFO, "CA: %s\n", m_allHashes[i]);
// certHash = (UINT8*)certHashCC->remove(m_allHashes[i]);
// if (certHash == NULL)
// {
// bFailed = true;
// break;
// }
// else
// {
// delete[] certHash;
// }
//}
//certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
//delete certHashCC;
if (!cascadeMatchesCC(pCC))
{
CAMsg::printMsg( LOG_INFO, "CostConfirmation has invalid price cert hashes!\n" );
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
(UINT8*)"CostConfirmation has invalid price cert hashes");
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_DATA;
}
// parse & set transferredBytes
//when using Prepayment, this check is outdated, but left in to notice the most crude errors/cheats
//The CC's transferredBytes should be equivalent to
//AccInfo's confirmed bytes + the Config's PrepaidInterval - the number of bytes transferred between
//requesting and receiving the CC
#ifdef DEBUG
CAMsg::printMsg( LOG_DEBUG, "received cost confirmation for %llu transferred bytes where confirmed bytes are %llu, we need %llu bytes to confirm"
", mix already counted %llu transferred bytes\n",
pCC->getTransferredBytes(), pAccInfo->confirmedBytes, pAccInfo->bytesToConfirm,
pAccInfo->transferredBytes);
#endif
if(pCC->getTransferredBytes() > (pAccInfo->transferredBytes+CALibProxytest::getOptions()->getPrepaidInterval()) )
{
CAMsg::printMsg( LOG_ERR, "Warning: ignoring this CC for account %llu "
"because it tries to confirm %lld prepaid bytes where only %u prepaid bytes are allowed (cc->tranferredbytes: %llu, accInfo->tranferredBytes: %llu)\n",
pAccInfo->accountNumber, (pCC->getTransferredBytes() - pAccInfo->transferredBytes),
CALibProxytest::getOptions()->getPrepaidInterval(),
pCC->getTransferredBytes(), pAccInfo->transferredBytes);
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
(UINT8*)"More bytes confirmed than allowed.");
XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);
if (errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
//mark as account empty has the effect is that the user can empty his prepaid amount and then will be kicked out.
pAccInfo->authFlags |= AUTH_FAKE;
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_DATA;
}
if (pCC->getTransferredBytes() < pAccInfo->confirmedBytes)
{
CAMsg::printMsg( LOG_ERR, "CostConfirmation has insufficient number of bytes:\n");
CAMsg::printMsg( LOG_ERR, "CC->transferredBytes: %llu < confirmedBytesBytes: %llu\n", pCC->getTransferredBytes(), pAccInfo->confirmedBytes);
if(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
{
//@todo: perhaps we should use another flag to indicate that this user should be kicked out.
pAccInfo->authFlags |= AUTH_FAKE;
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_WRONG_DATA;
}
/*
CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
(UINT8*)"Your CostConfirmation has a wrong number of transferred bytes");
DOM_Document errDoc;
err.toXmlDocument(errDoc);
pAccInfo->pControlChannel->sendXMLMessage(errDoc);*/
}
else if (pCC->getTransferredBytes() == pAccInfo->confirmedBytes && getPrepaidBytes(pAccInfo) != CALibProxytest::getOptions()->getPrepaidInterval())
{
CAMsg::printMsg(LOG_WARNING, "Received CostConfirmation for account %llu has no difference in bytes to current CC (%llu bytes).\n",
pAccInfo->accountNumber, pCC->getTransferredBytes());
}
else
{
/*
UINT8 tmp[32];
print64(tmp,pCC->getTransferredBytes());
CAMsg::printMsg( LOG_ERR, "Transferredbytes in CC: %s\n", tmp);
*/
SINT32 dbRet = E_UNKNOWN;
CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
if(dbInterface != NULL)
{
dbRet = dbInterface->storeCostConfirmation(*pCC, m_currentCascade);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
if (dbRet != E_SUCCESS)
{
UINT8 tmp[32];
print64(tmp,pCC->getAccountNumber());
CAMsg::printMsg( LOG_INFO, "CostConfirmation for account %s could not be stored in database!\n", tmp );
pAccInfo->authFlags |= AUTH_DATABASE;
}
else
{
#ifdef DEBUG
CAMsg::printMsg( LOG_INFO, "Handle CC: pCC->transBytes: %llu\n", pCC->getTransferredBytes() );
#endif
pAccInfo->confirmedBytes = pCC->getTransferredBytes();
if (pAccInfo->authFlags & AUTH_WAITING_FOR_FIRST_SETTLED_CC)
{
// initiate immediate settling
#ifdef DEBUG
UINT64 currentMillis;
UINT8 tmpStrCurrentMillis[50];
getcurrentTimeMillis(currentMillis);
print64(tmpStrCurrentMillis,currentMillis);
CAMsg::printMsg(LOG_DEBUG, "AccountingSettleThread: Settle ini: %s\n", tmpStrCurrentMillis);
#endif
m_pSettleThread->settle();
}
}
}
#ifdef DEBUG
CAMsg::printMsg(LOG_ERR, "Handle CC request: pAccInfo->confirmedBytes: %llu, ppAccInfo->transferredBytes: %llu\n",
pAccInfo->confirmedBytes, pAccInfo->transferredBytes);
#endif
if (pAccInfo->confirmedBytes >= pAccInfo->bytesToConfirm)
{
// the user confirmed everything we wanted; if a timeout has been set, it should be reset
pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
pAccInfo->lastHardLimitSeconds = time(NULL);
}
else
{
/*UINT8 tmp[32], tmp2[32], tmp3[32];
print64(tmp, pCC->getTransferredBytes());
print64(tmp2, pCC->getAccountNumber());
print64(tmp3, pAccInfo->bytesToConfirm);*/
CAMsg::printMsg(LOG_ERR, "AccountingSettleThread: Requested CC value has NOT been confirmed by account nr %llu! "
"Received Bytes: %llu/%llu "
"Client should not be allowed to login.\n",
pCC->getAccountNumber(),
pCC->getTransferredBytes(),
pAccInfo->bytesToConfirm);
if(pAccInfo->authFlags & AUTH_LOGIN_SKIP_SETTLEMENT)
{
CAMsg::printMsg( LOG_INFO, "Skip settlement revoked.\n");
pAccInfo->authFlags &= ~AUTH_LOGIN_SKIP_SETTLEMENT;
}
/*delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
pAccInfo->authFlags |= AUTH_FAKE;
return CAXMLErrorMessage::ERR_WRONG_DATA;*/
//m_pSettleThread->settle();
}
pAccInfo->bytesToConfirm = 0;
pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
delete pCC;
pCC = NULL;
pAccInfo->mutex->unlock();
return CAXMLErrorMessage::ERR_OK;
}
| SINT32 CAAccountingInstance::handleJapPacket | ( | fmHashTableEntry * | pHashEntry, |
| bool | a_bControlMessage, | ||
| bool | a_bMessageToJAP | ||
| ) | [static] |
This should be called by the FirstMix for every incoming Jap packet.
Definition at line 315 of file CAAccountingInstance.cpp.
References FINISH_STACK, handleJapPacket_internal(), and INIT_STACK.
Referenced by CAFirstMixA::accountTrafficDownstream(), CAFirstMixA::accountTrafficUpstream(), and CAFirstMixB::loop().
{
SINT32 ret = handleJapPacket_internal(pHashEntry, a_bControlMessage, a_bMessageToJAP);
INIT_STACK;
FINISH_STACK("CAAccountingInstance::handleJapPacket");
return ret;
}
| SINT32 CAAccountingInstance::handleJapPacket_internal | ( | fmHashTableEntry * | pHashEntry, |
| bool | a_bControlMessage, | ||
| bool | a_bMessageToJAP | ||
| ) | [static, private] |
Called by FirstMix for each incoming JAP packet.
Determines whether the packet should be let through or not
Possible return values, and FirstMix's reaction:
Do not make further checkings. Let the client use the remaining prepaid bytes, and then disconnect him afterwards. As the confirmedBytes are set to zero when the client connects and the account has been empty before, no other (unauthenticated) client may use these bytes.
Definition at line 335 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_DATABASE, AUTH_DELETE_ENTRY, AUTH_FATAL_ERROR, AUTH_HARD_LIMIT_REACHED, AUTH_INVALID_ACCOUNT, AUTH_LOGIN_NOT_FINISHED, AUTH_MULTIPLE_LOGIN, AUTH_OUTDATED_CC, AUTH_SENT_CC_REQUEST, AUTH_TIMEOUT_STARTED, AUTH_UNKNOWN, AUTH_WAITING_FOR_FIRST_SETTLED_CC, AccountLoginHashEntry::authFlags, t_accountinginfo::authFlags, AccountLoginHashEntry::authRemoveFlags, BEGIN_STACK, AccountLoginHashEntry::confirmedBytes, t_accountinginfo::confirmedBytes, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_DATABASE_ERROR, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, CAXMLErrorMessage::ERR_NO_CONFIRMATION, CAAccountingDBInterface::getConnection(), CAAccountingDBInterface::getCostConfirmation(), Hashtable::getMutex(), CALibProxytest::getOptions(), getPrepaidBytes(), CACmdLnOptions::getPrepaidInterval(), Hashtable::getValue(), CAXMLCostConfirmation::getXMLDocument(), HANDLE_PACKET_CLOSE_CONNECTION, HANDLE_PACKET_CONNECTION_OK, HANDLE_PACKET_CONNECTION_UNCHECKED, HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION, HARD_LIMIT_TIMEOUT, INIT_STACK, t_accountinginfo::lastHardLimitSeconds, CAMutex::lock(), m_currentAccountsHashtable, m_currentCascade, m_iHardLimitBytes, m_iSoftLimitBytes, MIXPACKET_SIZE, ms_pInstance, t_accountinginfo::mutex, t_accountinginfo::ownerRef, t_fmhashtableentry::pAccountingInfo, PACKETS_BEFORE_NEXT_CHECK, t_accountinginfo::pControlChannel, print64(), CAMsg::printMsg(), CAAccountingDBInterface::releaseConnection(), returnKickout(), returnPrepareKickout(), SAVE_STACK, sendCCRequest(), CAAbstractControlChannel::sendXMLMessage(), t_accountinginfo::sessionPackets, t_accountinginfo::transferredBytes, and CAMutex::unlock().
Referenced by handleJapPacket().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::handleJapPacket");
CAAccountingDBInterface *dbInterface = NULL;
if (pHashEntry == NULL || pHashEntry->pAccountingInfo == NULL)
{
return HANDLE_PACKET_CLOSE_CONNECTION;
}
tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
AccountLoginHashEntry* loginEntry = NULL;
CAXMLErrorMessage* err = NULL;
pAccInfo->mutex->lock();
if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
{
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CLOSE_CONNECTION;
}
//Should never happen since control flow assert that this method cannot be invoked
//when a login is not finished.
if ( (pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED) && !a_bMessageToJAP )
{
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: User violates login protocol");
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CLOSE_CONNECTION;
}
//still preparing to close connection -> no data is forwarded upstream and only control messages are
//sent downstream if a user connection is in this state.
if ( pAccInfo->authFlags & AUTH_FATAL_ERROR )
{
pAccInfo->mutex->unlock();
return HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION;
}
if (a_bControlMessage)
{
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CONNECTION_UNCHECKED;
}
else
{
// count the packet and continue checkings
pAccInfo->transferredBytes += MIXPACKET_SIZE;
pAccInfo->sessionPackets++;
#ifdef SDTFA
IncrementShmPacketCount();
#endif
}
if (pAccInfo->authFlags & AUTH_MULTIPLE_LOGIN)
{
return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
}
// do the following tests after a lot of Mix packets only (gain speed...)
if (!(pAccInfo->authFlags & (AUTH_TIMEOUT_STARTED | AUTH_HARD_LIMIT_REACHED | AUTH_ACCOUNT_EMPTY | AUTH_WAITING_FOR_FIRST_SETTLED_CC)) &&
pAccInfo->sessionPackets % PACKETS_BEFORE_NEXT_CHECK != 0)
{
//CAMsg::printMsg( LOG_DEBUG, "Now we gain some speed after %d session packets..., auth-flags: %x\n", pAccInfo->sessionPackets, pAccInfo->authFlags);
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CONNECTION_UNCHECKED;
}
SAVE_STACK("CAAccountingInstance::handleJapPacket", "before accounts hash");
if (!ms_pInstance->m_currentAccountsHashtable)
{
// accounting instance is dying...
return returnKickout(pAccInfo);
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
//Suppose, this section checks the flags set after settlement */
loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
if (loginEntry)
{
pAccInfo->authFlags &= ~loginEntry->authRemoveFlags;
//CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Remove flag: %d\n", loginEntry->authRemoveFlags);
/*if (loginEntry->ownerRef != pHashEntry)
{
// this is not the latest connection of this user; kick him out...
pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
}
else */
if (loginEntry->authFlags & AUTH_OUTDATED_CC)
{
loginEntry->authFlags &= ~AUTH_OUTDATED_CC;
UINT8 tmp[32];
print64(tmp,pAccInfo->accountNumber);
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Fixing bytes from outdated CC for account %s...\n", tmp);
// we had stored an outdated CC; insert confirmed bytes from current CC here and also update client
CAXMLCostConfirmation * pCC = NULL;
bool bSettled;
dbInterface = CAAccountingDBInterface::getConnection();//new CAAccountingDBInterface();
if(dbInterface != NULL)
{
dbInterface->getCostConfirmation(pAccInfo->accountNumber,
ms_pInstance->m_currentCascade,
&pCC,
bSettled);
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
/*ms_pInstance->m_dbInterface->getCostConfirmation(pAccInfo->accountNumber,
ms_pInstance->m_currentCascade, &pCC, bSettled);*/
if (pCC != NULL)
{
if (bSettled)
{
pAccInfo->transferredBytes += loginEntry->confirmedBytes - pAccInfo->confirmedBytes;
pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
loginEntry->confirmedBytes = 0;
pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
}
else
{
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: While trying to fix bytes from outdated CC,"
"another CC was received! Waiting for settlement... \n");
}
delete pCC;
pCC = NULL;
}
else
{
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Bytes from outdated CC could not be fixed!\n");
}
}
else if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
{
if(!(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY))
{
// Do not reset the flag, so that the confirmedBytes are always reset.
//loginEntry->authFlags &= ~AUTH_ACCOUNT_EMPTY;
pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
/* confirmedBytes = 0 leads to immediate disconnection.
* If confirmedBytes > 0, any remaining prepaid bytes may be used.
*/
pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
{
// this account is really empty; prevent an overflow in the prepaid bytes calculation
pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
}
//CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Account %llu is empty!\n", pAccInfo->accountNumber);
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty with %d prepaid bytes, (transferred bytes: %llu, confirmed bytes: %llu)!\n",
pAccInfo->accountNumber, getPrepaidBytes(pAccInfo), pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
}
}
else if (loginEntry->authFlags & AUTH_INVALID_ACCOUNT)
{
loginEntry->authFlags &= ~AUTH_INVALID_ACCOUNT;
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Found invalid account %llu ! Kicking out user...\n", pAccInfo->accountNumber);
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
}
else if (loginEntry->authFlags & AUTH_BLOCKED)
{
loginEntry->authFlags &= ~AUTH_BLOCKED;
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with blocked account %llu !\n", pAccInfo->accountNumber);
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED);
}
else if (loginEntry->authFlags & AUTH_DATABASE)
{
loginEntry->authFlags &= ~AUTH_DATABASE;
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with account %llu due to database error...\n", pAccInfo->accountNumber);
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_DATABASE_ERROR);
}
else if (loginEntry->authFlags & AUTH_UNKNOWN)
{
loginEntry->authFlags &= ~AUTH_UNKNOWN;
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Unknown error, account %llu! Kicking out user...\n", pAccInfo->accountNumber);
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR);
}
}
else
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: handleJapPacket %s,%s did not find user login hash entry for account %llu, owner/accInfo: %p/%p!\n",
(a_bMessageToJAP ? "downstream" : "upstream"),
(a_bControlMessage ? "ctl" : "data"),
pAccInfo->accountNumber, pAccInfo->ownerRef, pHashEntry->pAccountingInfo);
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
return returnKickout(pAccInfo);
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
{
// There should be no time limit. The connections is simply closed after all prepaid bytes are gone.
pAccInfo->lastHardLimitSeconds = time(NULL);
//#ifdef DEBUG
//#endif
if (getPrepaidBytes(pAccInfo) <= 0)
{
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty! Kicking out user...\n",
pAccInfo->accountNumber);
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
}
else
{
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CONNECTION_OK;
}
}
//pAccInfo->mutex->lock();
SAVE_STACK("CAAccountingInstance::handleJapPacket", "before err");
if (err)
{
return returnPrepareKickout(pAccInfo, err);
}
//----------------------------------------------------------
// ****** Hardlimit cost confirmation check **********
//counting unconfirmed bytes is not necessary anymore, since we deduct from prepaid bytes
//UINT32 unconfirmedBytes=diff64(pAccInfo->transferredBytes,pAccInfo->confirmedBytes);
//confirmed and transferred bytes are cumulative, so they use UINT64 to store potentially huge values
//prepaid Bytes as the difference will be much smaller, but might be negative, so we cast to signed int
SINT32 prepaidBytes = getPrepaidBytes(pAccInfo);
if (prepaidBytes < 0 || prepaidBytes <= (SINT32) ms_pInstance->m_iHardLimitBytes)
{
UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
if ((pAccInfo->authFlags & AUTH_HARD_LIMIT_REACHED) == 0)
{
pAccInfo->lastHardLimitSeconds = time(NULL);
pAccInfo->authFlags |= AUTH_HARD_LIMIT_REACHED;
}
#ifdef DEBUG
CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Hard limit of %d bytes triggered in %d seconds \n",
ms_pInstance->m_iHardLimitBytes,
(pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT - time(NULL)));
#endif
if ( ( (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT) && (prepaidBytes <= 0) )
|| (prepaidBytes < 0 && (UINT32)(prepaidBytes * (-1)) >= prepaidInterval) )
{
//#ifdef DEBUG
char* strReason;
if (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT)
{
strReason = "timeout";
}
else
{
strReason = "negative prepaid interval exceeded";
}
CAMsg::printMsg( LOG_INFO, "Accounting instance: User refused "
"to send cost confirmation (HARDLIMIT EXCEEDED, %s). "
"PrepaidBytes were: %d\n", strReason, prepaidBytes);
//#endif
//ms_pInstance->m_pIPBlockList->insertIP( pHashEntry->peerIP );
pAccInfo->lastHardLimitSeconds = 0;
return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_CONFIRMATION));
}
else
{
if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
{
sendCCRequest(pAccInfo);
}
}
}
else
{
pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
}
//-------------------------------------------------------
// *** SOFT LIMIT CHECK *** is it time to request a new cost confirmation?
if ( prepaidBytes < 0 || prepaidBytes <= (SINT32) ms_pInstance->m_iSoftLimitBytes )
{
#ifdef DEBUG
CAMsg::printMsg(LOG_ERR, "soft limit of %d bytes triggered \n",ms_pInstance->m_iSoftLimitBytes);
#endif
if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
{//we have sent a first CC request
// no CC request sent yet --> send a first CC request
sendCCRequest(pAccInfo);
}
}// end of soft limit exceeded
//everything is fine! let the packet pass thru
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CONNECTION_OK;
}
| static SINT32 CAAccountingInstance::init | ( | CAFirstMix * | callingMix | ) | [inline, static] |
Returns a reference to the Singleton instance.
Definition at line 121 of file CAAccountingInstance.hpp.
References CAAccountingInstance(), E_SUCCESS, MONITORING_FIRE_PAY_EVENT, and ms_pInstance.
{
ms_pInstance = new CAAccountingInstance(callingMix);
MONITORING_FIRE_PAY_EVENT(ev_pay_aiInited);
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::initTableEntry | ( | fmHashTableEntry * | pHashEntry | ) | [static] |
This must be called whenever a JAP is connecting to init our per-user data structures.
Definition at line 2511 of file CAAccountingInstance.cpp.
References AUTH_HARD_LIMIT_REACHED, AUTH_LOGIN_NOT_FINISHED, AUTH_SENT_ACCOUNT_REQUEST, AUTH_SENT_CC_REQUEST, AUTH_TIMEOUT_STARTED, AUTH_WAITING_FOR_FIRST_SETTLED_CC, t_accountinginfo::authFlags, t_accountinginfo::authTimeoutStartSeconds, BEGIN_STACK, t_accountinginfo::bytesToConfirm, t_accountinginfo::clientVersion, t_accountinginfo::confirmedBytes, E_SUCCESS, E_UNKNOWN, FINISH_STACK, t_fmhashtableentry::id, INIT_STACK, t_accountinginfo::lastHardLimitSeconds, t_accountinginfo::mutex, t_accountinginfo::nrInQueue, t_accountinginfo::ownerRef, t_fmhashtableentry::pAccountingInfo, SAVE_STACK, t_accountinginfo::sessionPackets, t_accountinginfo::transferredBytes, and t_accountinginfo::userID.
Referenced by CAAccountingControlChannel::CAAccountingControlChannel().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::initTableEntry");
//ms_pInstance->m_pMutex->lock();
if (pHashEntry == NULL)
{
FINISH_STACK("CAAccountingInstance::initTableEntry:NULL");
return E_UNKNOWN;
}
pHashEntry->pAccountingInfo = new tAiAccountingInfo;
memset( pHashEntry->pAccountingInfo, 0, sizeof( tAiAccountingInfo ) );
SAVE_STACK("CAAccountingInstance::initTableEntry", "After memset");
pHashEntry->pAccountingInfo->authFlags =
AUTH_SENT_ACCOUNT_REQUEST | AUTH_TIMEOUT_STARTED |
AUTH_HARD_LIMIT_REACHED | AUTH_WAITING_FOR_FIRST_SETTLED_CC |
AUTH_SENT_CC_REQUEST | AUTH_LOGIN_NOT_FINISHED; // prevents multiple CC requests on login
pHashEntry->pAccountingInfo->authTimeoutStartSeconds = time(NULL);
pHashEntry->pAccountingInfo->lastHardLimitSeconds = time(NULL);
pHashEntry->pAccountingInfo->sessionPackets = 0;
pHashEntry->pAccountingInfo->transferredBytes = 0;
pHashEntry->pAccountingInfo->confirmedBytes = 0;
pHashEntry->pAccountingInfo->bytesToConfirm = 0;
pHashEntry->pAccountingInfo->nrInQueue = 0;
pHashEntry->pAccountingInfo->userID = pHashEntry->id;
pHashEntry->pAccountingInfo->ownerRef = pHashEntry;
pHashEntry->pAccountingInfo->clientVersion = NULL;
pHashEntry->pAccountingInfo->mutex = new CAMutex;
//ms_pInstance->m_pMutex->unlock();
FINISH_STACK("CAAccountingInstance::initTableEntry");
return E_SUCCESS;
}
| static SINT32 CAAccountingInstance::isIPAddressBlocked | ( | const UINT8 | ip[4] | ) | [inline, static] |
Check if an IP address is temporarily blocked by the accounting instance.
This should be called by the FirstMix when a JAP is connecting.
| 1 | if the given IP is blocked |
| 0 | if it is not blocked |
Definition at line 167 of file CAAccountingInstance.hpp.
{
//return ms_pInstance->m_pIPBlockList->checkIP(ip);
return 0;
}
| SINT32 CAAccountingInstance::loginProcessStatus | ( | fmHashTableEntry * | pHashEntry | ) | [static] |
Definition at line 1299 of file CAAccountingInstance.cpp.
References AUTH_LOGIN_FAILED, AUTH_LOGIN_NOT_FINISHED, AUTH_LOGIN_SKIP_SETTLEMENT, AUTH_MULTIPLE_LOGIN, t_accountinginfo::authFlags, CAMutex::lock(), t_accountinginfo::mutex, t_fmhashtableentry::pAccountingInfo, and CAMutex::unlock().
Referenced by CAFirstMix::doUserLogin_internal().
{
SINT32 ret = 0;
if(pHashEntry == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(pHashEntry->pAccountingInfo == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
if(pHashEntry->pAccountingInfo->mutex == NULL)
{
return ret |= AUTH_LOGIN_FAILED;
}
pHashEntry->pAccountingInfo->mutex->lock();
ret = pHashEntry->pAccountingInfo->authFlags &
(AUTH_LOGIN_NOT_FINISHED | AUTH_LOGIN_FAILED | AUTH_LOGIN_SKIP_SETTLEMENT | AUTH_MULTIPLE_LOGIN);
pHashEntry->pAccountingInfo->mutex->unlock();
return ret;
}
| static SINT32 CAAccountingInstance::makeAccountRequest | ( | XERCES_CPP_NAMESPACE::DOMDocument *& | doc | ) | [static, private] |
| SINT32 CAAccountingInstance::makeCCRequest | ( | const UINT64 | accountNumber, |
| const UINT64 | transferredBytes, | ||
| XERCES_CPP_NAMESPACE::DOMDocument *& | doc | ||
| ) | [static, private] |
Definition at line 1046 of file CAAccountingInstance.cpp.
References BEGIN_STACK, createDOMDocument(), createDOMElement(), E_SUCCESS, FINISH_STACK, getDOMChildByName(), INIT_STACK, m_preparedCCRequest, and setDOMElementValue().
Referenced by sendCCRequest().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::makeCCRequest");
DOMNode* elemCC=NULL;
doc = createDOMDocument();
doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
DOMElement* elemAccount = createDOMElement(doc,"AccountNumber");
setDOMElementValue(elemAccount, accountNumber);
elemCC->appendChild(elemAccount);
DOMElement* elemBytes = createDOMElement(doc,"TransferredBytes");
setDOMElementValue(elemBytes, transferredBytes);
elemCC->appendChild(elemBytes);
FINISH_STACK("CAAccountingInstance::makeCCRequest");
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::makeInitialCCRequest | ( | CAXMLCostConfirmation * | pCC, |
| XERCES_CPP_NAMESPACE::DOMDocument *& | doc, | ||
| SINT32 | prepaidBytes | ||
| ) | [static, private] |
new initialCCRequest containing the last CC and the prepaid bytes (this is a replacement for sending the prepaid with the challenge which is now deprecated).
Definition at line 1020 of file CAAccountingInstance.cpp.
References createDOMDocument(), createDOMElement(), E_SUCCESS, E_UNKNOWN, getDOMChildByName(), CAXMLCostConfirmation::getXMLDocument(), m_preparedCCRequest, CAMsg::printMsg(), setDOMElementAttribute(), and setDOMElementValue().
Referenced by sendInitialCCRequest().
{
if( (pCC == NULL) || (pCC->getXMLDocument() == NULL) ||
(pCC->getXMLDocument()->getDocumentElement() == NULL) )
{
CAMsg::printMsg(LOG_ERR, "Error creating initial CCrequest (pCC ref: %p)\n", pCC);
return E_UNKNOWN;
}
DOMNode* elemCC=NULL;
doc = createDOMDocument();
DOMNode *ccRoot = doc->importNode(pCC->getXMLDocument()->getDocumentElement(),true);
doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
setDOMElementAttribute(doc->getDocumentElement(), "initialCC", true);
DOMElement *elemPrepaidBytes = createDOMElement(doc, "PrepaidBytes");
setDOMElementValue(elemPrepaidBytes, prepaidBytes);
getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
if(elemCC == NULL)
{
return E_UNKNOWN;
}
doc->getDocumentElement()->replaceChild(ccRoot, elemCC);
doc->getDocumentElement()->appendChild(elemPrepaidBytes);
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::newSettlementTransaction | ( | ) | [static] |
Definition at line 2762 of file CAAccountingInstance.cpp.
References __newSettlementTransaction(), E_SUCCESS, and MAX_SETTLED_CCS.
Referenced by CAFirstMix::doUserLogin_internal(), and CAAccountingSettleThread::mainLoop().
{
UINT32 settledCCs = 0;
SINT32 retVal;
do
{
retVal = __newSettlementTransaction(&settledCCs);
}
while(settledCCs >= MAX_SETTLED_CCS && retVal == E_SUCCESS);
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!
}
| SINT32 CAAccountingInstance::prepareCCRequest | ( | CAMix * | callingMix, |
| UINT8 * | a_AiName | ||
| ) | [private] |
creating the xml of a new CC is really the responsability of the CAXMLCostConfirmation class knowledge about the structure of a CC's XML should be encapsulated in it TODO: add constructor to that class that takes accountnumber, transferredbytes etc as params (should use a template internally into which it only inserts accNumber and bytes,to speed things up TODO: add toXMLElement method then replace manually building the xml here with contructing a CAXMLCostConfirmation and just add the xml returned by its toXMLElement method
| callingMix,: | the Mix instance to which the AI belongs (needed to get cascadeInfo to extract the price certificates to include in cost confirmations) |
Definition at line 886 of file CAAccountingInstance.cpp.
References createDOMDocument(), createDOMElement(), E_SUCCESS, E_UNKNOWN, CABase64::encode(), getDOMChildByName(), getElementsByTagName(), CAMix::getMixCascadeInfo(), len, m_allHashes, m_allHashesLen, m_currentCascade, m_preparedCCRequest, DOM_Output::makeCanonical(), CAMsg::printMsg(), setDOMElementAttribute(), setDOMElementValue(), and strtrim().
Referenced by CAAccountingInstance().
{
m_preparedCCRequest = createDOMDocument();
DOMElement* elemRoot = createDOMElement(m_preparedCCRequest,"PayRequest");
setDOMElementAttribute(elemRoot,"version",(UINT8*) "1.0");
m_preparedCCRequest->appendChild(elemRoot);
DOMElement* elemCC = createDOMElement(m_preparedCCRequest,"CC");
setDOMElementAttribute(elemCC,"version",(UINT8*) "1.2");
elemRoot->appendChild(elemCC);
DOMElement* elemAiName = createDOMElement(m_preparedCCRequest,"AiID");
setDOMElementValue(elemAiName, a_AiName);
elemCC->appendChild(elemAiName);
//extract price certificate elements from cascadeInfo
//get cascadeInfo from CAMix(which makeCCRequest needs to extract the price certs
XERCES_CPP_NAMESPACE::DOMDocument* cascadeInfoDoc=NULL;
callingMix->getMixCascadeInfo(cascadeInfoDoc);
DOMElement* cascadeInfoElem = cascadeInfoDoc->getDocumentElement();
DOMNodeList* allMixes = getElementsByTagName(cascadeInfoElem,"Mix");
UINT32 nrOfMixes = allMixes->getLength();
DOMNode** mixNodes = new DOMNode*[nrOfMixes]; //so we can use separate loops for extracting, hashing and appending
DOMNode* curMixNode=NULL;
for (UINT32 i = 0, j = 0, count = nrOfMixes; i < count; i++, j++){
//cant use getDOMChildByName from CAUtil here yet, since it will always return the first child
curMixNode = allMixes->item(i);
if (getDOMChildByName(curMixNode,"PriceCertificate",mixNodes[j],true) != E_SUCCESS)
{
j--;
nrOfMixes--;
}
}
//hash'em, and get subjectkeyidentifiers
UINT8 digest[SHA_DIGEST_LENGTH];
m_allHashes=new UINT8*[nrOfMixes];
m_allHashesLen = nrOfMixes;
UINT8** allSkis=new UINT8*[nrOfMixes];
DOMNode* skiNode=NULL;
for (UINT32 i = 0; i < nrOfMixes; i++){
UINT8* out=new UINT8[5000];
UINT32 outlen=5000;
DOM_Output::makeCanonical(mixNodes[i],out,&outlen);
out[outlen] = 0;
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "price cert to be hashed: %s",out);
#endif
SHA1(out,outlen,digest);
delete[] out;
out = NULL;
UINT32 len = 1024;
UINT8* tmpBuff = new UINT8[len+1];
memset(tmpBuff, 0, len+1);
if(CABase64::encode(digest,SHA_DIGEST_LENGTH,tmpBuff,&len)!=E_SUCCESS)
return E_UNKNOWN;
//tmpBuff[len]=0;
//line breaks might have been added, and would lead to database problems
strtrim(tmpBuff); //return value ohny significant for NULL or all-whitespace string, ignore
m_allHashes[i] = tmpBuff;
CAMsg::printMsg(LOG_DEBUG,"Price certificate hash of Mix %u is: %s\n", i, m_allHashes[i]);
//do not delete tmpBuff here, since we're using allHashes below
if (getDOMChildByName(mixNodes[i],"SubjectKeyIdentifier",skiNode,true) != E_SUCCESS)
{
CAMsg::printMsg(LOG_CRIT,"Could not get mix id from price cert");
}
allSkis[i] = (UINT8*) XMLString::transcode(skiNode->getFirstChild()->getNodeValue());
}
//concatenate the hashes, and store for future reference to identify the cascade
m_currentCascade = new UINT8[256];
memset(m_currentCascade, 0, (sizeof(UINT8)*256 ));
for (UINT32 j = 0; j < nrOfMixes; j++)
{
//check for hash value size (should always be OK)
if (strlen((const char*)m_currentCascade) > ( 256 - strlen((const char*)m_allHashes[j]) ) )
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance::prepareCCRequest: "
"Too many/too long hash values, ran out of allocated memory\n");
return E_UNKNOWN;
}
if (j == 0)
{
m_currentCascade = (UINT8*) strcpy( (char*) m_currentCascade,(const char*)m_allHashes[j]);
} else
{
m_currentCascade = (UINT8*) strcat((char*)m_currentCascade,(char*)m_allHashes[j]);
}
}
//and append to CC
DOMElement* elemPriceCerts = createDOMElement(m_preparedCCRequest,"PriceCertificates");
DOMElement* elemCert=NULL;
for (UINT32 i = 0; i < nrOfMixes; i++)
{
elemCert = createDOMElement(m_preparedCCRequest,"PriceCertHash");
//CAMsg::printMsg(LOG_DEBUG,"hash to be inserted in cc: index %d, value %s\n",i,m_allHashes[i]);
setDOMElementValue(elemCert,m_allHashes[i]);
//delete[] allHashes[i];
setDOMElementAttribute(elemCert,"id",allSkis[i]);
setDOMElementAttribute(elemCert, "position", i);
if (i == 0)
{
setDOMElementAttribute(elemCert,"isAI",(UINT8*)"true");
}
elemPriceCerts->appendChild(elemCert);
}
elemCC->appendChild(elemPriceCerts);
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "finished method makeCCRequest\n");
#endif
delete[] mixNodes;
mixNodes = NULL;
//delete[] allHashes;
delete[] allSkis;
allSkis = NULL;
return E_SUCCESS;
}
| SINT32 CAAccountingInstance::processJapMessage | ( | fmHashTableEntry * | pHashEntry, |
| const XERCES_CPP_NAMESPACE::DOMDocument * | a_DomDoc | ||
| ) | [static] |
Handle a user (xml) message sent to us by the Jap through the ControlChannel.
Handle a user (xml) message sent to us by the Jap.
This function determines what type of message we have and sends the appropriate handle...() function to the ai thread.
This function is running inside the AiThread. It determines what type of message we have and calls the appropriate handle...() function
pHashEntry->pAccountingInfo->mutex->lock(); pItem->pAccInfo->nrInQueue++; ret = ms_pInstance->m_aiThreadPool->addRequest(processThread, pItem); if (ret !=E_SUCCESS) { pItem->pAccInfo->nrInQueue--; CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Process could not add to AI thread pool!\n" ); delete pItem->pDomDoc; delete pItem; } pHashEntry->pAccountingInfo->mutex->unlock(); return ret; }
Definition at line 1106 of file CAAccountingInstance.cpp.
References AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_INVALID_ACCOUNT, AUTH_LOGIN_SKIP_SETTLEMENT, t_accountinginfo::authFlags, BEGIN_STACK, E_SUCCESS, E_UNKNOWN, CAXMLErrorMessage::ERR_OK, FINISH_STACK, getPrepaidBytes(), handleAccountCertificate(), handleChallengeResponse(), handleCostConfirmation(), INIT_STACK, ms_pInstance, t_fmhashtableentry::pAccountingInfo, CAMsg::printMsg(), processJapMessageLoginHelper(), and SAVE_STACK.
Referenced by CAAccountingControlChannel::processXMLMessage().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::processJapMessage");
if (pHashEntry == NULL)
{
return E_UNKNOWN;
}
DOMElement* root = a_DomDoc->getDocumentElement();
if(root == NULL)
{
CAMsg::printMsg(LOG_DEBUG, "ProcessJapMessage: getDocument Element is null!!!\n" );
return E_UNKNOWN;
}
char* docElementName = XMLString::transcode(root->getTagName());
SINT32 hf_ret = 0;
// what type of message is it?
if ( strcmp( docElementName, "AccountCertificate" ) == 0 )
{
#ifdef DEBUG
CAMsg::printMsg( LOG_DEBUG, "Received an AccountCertificate. Calling handleAccountCertificate()\n" );
#endif
//handleFunc = &CAAccountingInstance::handleAccountCertificate;
hf_ret = ms_pInstance->handleAccountCertificate( pHashEntry->pAccountingInfo, root );
processJapMessageLoginHelper(pHashEntry, hf_ret, false);
}
else if ( strcmp( docElementName, "Response" ) == 0)
{
#ifdef DEBUG
CAMsg::printMsg( LOG_DEBUG, "Received a Response (challenge-response)\n" );
#endif
//handleFunc = &CAAccountingInstance::handleChallengeResponse;
hf_ret = ms_pInstance->handleChallengeResponse( pHashEntry->pAccountingInfo, root );
processJapMessageLoginHelper(pHashEntry, hf_ret, false);
/*if(hf_ret != CAXMLErrorMessage::ERR_OK)
{
unlockLogin(pHashEntry);
}
else*/
if(hf_ret == (SINT32) CAXMLErrorMessage::ERR_OK)
{
//CAMsg::printMsg( LOG_DEBUG, "Prepaid bytes are: %d\n", getPrepaidBytes(pHashEntry->pAccountingInfo));
if( (getPrepaidBytes(pHashEntry->pAccountingInfo) > 0) &&
!(pHashEntry->pAccountingInfo->authFlags &
(AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) )
{
pHashEntry->pAccountingInfo->authFlags |= AUTH_LOGIN_SKIP_SETTLEMENT;
}
}
}
else if ( strcmp( docElementName, "CC" ) == 0 )
{
#ifdef DEBUG
CAMsg::printMsg( LOG_DEBUG, "Received a CC. Calling handleCostConfirmation()\n" );
#endif
//handleFunc = &CAAccountingInstance::handleCostConfirmation;
hf_ret = ms_pInstance->handleCostConfirmation( pHashEntry->pAccountingInfo, root );
processJapMessageLoginHelper(pHashEntry, hf_ret, true);
/*if(hf_ret != CAXMLErrorMessage::ERR_OK)
{
unlockLogin(pHashEntry);
}*/
}
else
{
CAMsg::printMsg( LOG_ERR,
"AI Received XML message with unknown root element \"%s\". This is not accepted!\n",
docElementName
);
SAVE_STACK("CAAccountingInstance::processJapMessage", "error");
XMLString::release(&docElementName);
return E_UNKNOWN;
}
XMLString::release(&docElementName);
// remove these lines if AI thread pool is used (see @todo above)
//(ms_pInstance->*handleFunc)(pHashEntry->pAccountingInfo, root );
FINISH_STACK("CAAccountingInstance::processJapMessage");
return E_SUCCESS;
}
| void CAAccountingInstance::processJapMessageLoginHelper | ( | fmHashTableEntry * | pHashEntry, |
| UINT32 | handlerReturnvalue, | ||
| bool | finishLogin | ||
| ) | [static, private] |
Definition at line 1218 of file CAAccountingInstance.cpp.
References AUTH_FAKE, AUTH_LOGIN_FAILED, AUTH_LOGIN_NOT_FINISHED, AUTH_MULTIPLE_LOGIN, t_accountinginfo::authFlags, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, CAXMLErrorMessage::ERR_OK, CAMutex::lock(), t_accountinginfo::mutex, t_fmhashtableentry::pAccountingInfo, t_accountinginfo::pControlChannel, CAAbstractControlChannel::sendXMLMessage(), CAAbstractXMLEncodable::toXmlDocument(), and CAMutex::unlock().
Referenced by processJapMessage().
{
if(pHashEntry->pAccountingInfo != NULL)
{
if(pHashEntry->pAccountingInfo->mutex == NULL)
{
return;
}
pHashEntry->pAccountingInfo->mutex->lock();
if(pHashEntry->pAccountingInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
{
if(handlerReturnValue != CAXMLErrorMessage::ERR_OK)
{
pHashEntry->pAccountingInfo->authFlags &= ~AUTH_LOGIN_NOT_FINISHED;
pHashEntry->pAccountingInfo->authFlags |= AUTH_LOGIN_FAILED;
CAXMLErrorMessage *err = NULL;
XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
/*if(pHashEntry->pAccountingInfo->authFlags & AUTH_BLOCKED )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED,
(UINT8 *) "AI login: access denied because your account is blocked");
}
else if(pHashEntry->pAccountingInfo->authFlags & AUTH_ACCOUNT_EMPTY )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY,
(UINT8 *) "AI login: access denied because your account is empty");
}
else if(pHashEntry->pAccountingInfo->authFlags & AUTH_INVALID_ACCOUNT )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_BALANCE,
(UINT8 *) "AI login: access denied because your account is not valid");
}
else */ if(pHashEntry->pAccountingInfo->authFlags & AUTH_FAKE )
{
err = new CAXMLErrorMessage(handlerReturnValue);
}
else if(pHashEntry->pAccountingInfo->authFlags & AUTH_MULTIPLE_LOGIN )
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN,
(UINT8*)"You are already logged in.");
}
else
{
err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR,
(UINT8 *) "AI login: error occured while connecting, access denied");
}
if(err != NULL)
{
err->toXmlDocument(errDoc);
pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
delete err;
err = NULL;
}
if(errDoc != NULL)
{
errDoc->release();
errDoc = NULL;
}
/*sendAILoginConfirmation(pHashEntry->pAccountingInfo,
CAXMLErrorMessage::ERR_BLOCKED,
(UINT8*) "AI access denied");*/
}
else if(lastLoginMessage)
{
//CAMsg::printMsg( LOG_ERR, "User successfully logged in\n");
pHashEntry->pAccountingInfo->authFlags &= ~AUTH_LOGIN_NOT_FINISHED;
}
}
pHashEntry->pAccountingInfo->mutex->unlock();
}
}
| THREAD_RETURN CAAccountingInstance::processThread | ( | void * | a_param | ) | [static, private] |
The main loop of the AI thread - reads messages from the queue and starts process threads for these messages.
Processes JAP messages asynchronously by calls to the appropriate handlers.
Definition at line 266 of file CAAccountingInstance.cpp.
References AUTH_DELETE_ENTRY, t_accountinginfo::authFlags, BEGIN_STACK, FINISH_STACK, CAAccountingInstance::t_aiqueueitem::handleFunc, INIT_STACK, CAMutex::lock(), ms_pInstance, t_accountinginfo::mutex, t_accountinginfo::nrInQueue, CAAccountingInstance::t_aiqueueitem::pAccInfo, CAAccountingInstance::t_aiqueueitem::pDomDoc, CAMsg::printMsg(), THREAD_RETURN_SUCCESS, and CAMutex::unlock().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::processThread");
aiQueueItem* item = (aiQueueItem*)a_param;
bool bDelete = false;
DOMElement *elem = item->pDomDoc->getDocumentElement();
// call the handle function
(ms_pInstance->*(item->handleFunc))(item->pAccInfo, elem);
item->pAccInfo->mutex->lock();
item->pAccInfo->nrInQueue--;
if (item->pAccInfo->authFlags & AUTH_DELETE_ENTRY &&
item->pAccInfo->nrInQueue == 0)
{
/*
* There is no more entry of this connection in the queue,
* and the connection is closed. We have to delete the entry.
*/
bDelete = true;
CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Deleting account entry from AI thread.\n");
}
if (item->pAccInfo->nrInQueue < 0)
{
CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI thread found negative handle queue!\n");
}
item->pAccInfo->mutex->unlock();
if (bDelete)
{
delete item->pAccInfo->mutex;
item->pAccInfo->mutex = NULL;
delete item->pAccInfo;
item->pAccInfo = NULL;
}
delete item->pDomDoc;
item->pDomDoc = NULL;
delete item;
item = NULL;
FINISH_STACK("CAAccountingInstance::processThread");
THREAD_RETURN_SUCCESS;
}
| SINT32 CAAccountingInstance::returnKickout | ( | tAiAccountingInfo * | pAccInfo | ) | [static, private] |
When receiving this message, the Mix should kick the user out immediately.
Definition at line 714 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, HANDLE_PACKET_CLOSE_CONNECTION, t_accountinginfo::mutex, print64(), CAMsg::printMsg(), setPrepaidBytesToZero_internal(), and CAMutex::unlock().
Referenced by handleJapPacket_internal().
{
UINT8 tmp[32];
print64(tmp,pAccInfo->accountNumber);
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: should kick out user with account %s now...\n", tmp);
setPrepaidBytesToZero_internal(pAccInfo);
pAccInfo->mutex->unlock();
return HANDLE_PACKET_CLOSE_CONNECTION;
}
| SINT32 CAAccountingInstance::returnPrepareKickout | ( | tAiAccountingInfo * | pAccInfo, |
| CAXMLErrorMessage * | a_error | ||
| ) | [static, private] |
Definition at line 744 of file CAAccountingInstance.cpp.
References AUTH_FATAL_ERROR, t_accountinginfo::authFlags, HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION, t_accountinginfo::mutex, t_accountinginfo::pControlChannel, CAMsg::printMsg(), CAAbstractControlChannel::sendXMLMessage(), CAAbstractXMLEncodable::toXmlDocument(), and CAMutex::unlock().
Referenced by handleJapPacket_internal().
{
pAccInfo->authFlags |= AUTH_FATAL_ERROR;
if (a_error)
{
//CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Sending error message...\n");
XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
a_error->toXmlDocument(doc);
delete a_error;
a_error = NULL;
//pAccInfo->sessionPackets = 0; // allow some pakets to pass by to send the control message
CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before prepare Kickout send...\n");
pAccInfo->pControlChannel->sendXMLMessage(doc);
if (doc != NULL)
{
doc->release();
doc = NULL;
}
}
else
{
CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Should send error message, but none is available!\n");
}
pAccInfo->mutex->unlock();
return HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION;
}
| SINT32 CAAccountingInstance::sendAILoginConfirmation | ( | tAiAccountingInfo * | pAccInfo, |
| const UINT32 | code, | ||
| UINT8 * | message | ||
| ) | [static, private] |
Definition at line 1071 of file CAAccountingInstance.cpp.
References createDOMDocument(), createDOMElement(), DOM_Output::dumpToMem(), E_SUCCESS, t_accountinginfo::pControlChannel, CAMsg::printMsg(), CAAbstractControlChannel::sendXMLMessage(), setDOMElementAttribute(), and setDOMElementValue().
Referenced by finishLoginProcess().
{
SINT32 sendSuccess = E_SUCCESS;
XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
DOMElement *elemRoot = createDOMElement(doc, "LoginConfirmation");
setDOMElementAttribute(elemRoot, "code", code);
setDOMElementValue(elemRoot, message);
doc->appendChild(elemRoot);
#ifdef DEBUG
UINT32 debuglen = 3000;
UINT8 debugout[3000];
DOM_Output::dumpToMem(doc,debugout,&debuglen);
debugout[debuglen] = 0;
CAMsg::printMsg(LOG_DEBUG, "the AILogin Confirmation sent looks like this: %s \n",debugout);
#endif
sendSuccess = pAccInfo->pControlChannel->sendXMLMessage(doc);
if (doc != NULL)
{
doc->release();
doc = NULL;
}
return sendSuccess;
}
| SINT32 CAAccountingInstance::sendCCRequest | ( | tAiAccountingInfo * | pAccInfo | ) | [static, private] |
Definition at line 799 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_SENT_CC_REQUEST, t_accountinginfo::authFlags, BEGIN_STACK, t_accountinginfo::bytesToConfirm, DOM_Output::dumpToMem(), E_SUCCESS, CALibProxytest::getOptions(), CACmdLnOptions::getPrepaidInterval(), INIT_STACK, makeCCRequest(), t_accountinginfo::pControlChannel, CAMsg::printMsg(), CAAbstractControlChannel::sendXMLMessage(), and t_accountinginfo::transferredBytes.
Referenced by handleChallengeResponse_internal(), and handleJapPacket_internal().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::sendCCRequest");
XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
{
// do not send further CC requests for this account
return E_SUCCESS;
}
// prepaid bytes are "confirmed bytes - transfered bytes"
//UINT64 bytesToConfirm = pAccInfo->confirmedBytes + (prepaidInterval) - (pAccInfo->confirmedBytes - pAccInfo->transferredBytes);
pAccInfo->bytesToConfirm = (prepaidInterval) + pAccInfo->transferredBytes;
makeCCRequest(pAccInfo->accountNumber, pAccInfo->bytesToConfirm, doc);
//pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "CC request sent for %llu bytes, transferrred bytes: %llu bytes.\n",pAccInfo->bytesToConfirm, pAccInfo->transferredBytes);
CAMsg::printMsg(LOG_DEBUG, "prepaid Interval: %u \n",prepaidInterval);
UINT32 debuglen = 3000;
UINT8 debugout[3000];
DOM_Output::dumpToMem(doc,debugout,&debuglen);
debugout[debuglen] = 0;
CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
#endif
//FINISH_STACK("CAAccountingInstance::sendCCRequest");
SINT32 ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
if (doc != NULL)
{
doc->release();
doc = NULL;
}
return ret;
}
| SINT32 CAAccountingInstance::sendInitialCCRequest | ( | tAiAccountingInfo * | pAccInfo, |
| CAXMLCostConfirmation * | pCC, | ||
| SINT32 | prepaidBytes | ||
| ) | [static, private] |
Definition at line 773 of file CAAccountingInstance.cpp.
References DOM_Output::dumpToMem(), E_SUCCESS, E_UNKNOWN, makeInitialCCRequest(), t_accountinginfo::pControlChannel, CAMsg::printMsg(), and CAAbstractControlChannel::sendXMLMessage().
Referenced by handleChallengeResponse_internal().
{
XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
SINT32 ret = makeInitialCCRequest(pCC, doc, prepaidBytes);
if( (ret != E_SUCCESS) || (doc == NULL))
{
CAMsg::printMsg(LOG_ERR, "cannot send initial CC request, ret: %d\n", ret);
return E_UNKNOWN;
}
#ifdef DEBUG
UINT32 debuglen = 3000;
UINT8 debugout[3000];
DOM_Output::dumpToMem(doc,debugout,&debuglen);
debugout[debuglen] = 0;
CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
#endif
ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
if (doc != NULL)
{
doc->release();
doc = NULL;
}
return ret;
}
| void CAAccountingInstance::setPrepaidBytesToZero | ( | tAiAccountingInfo * | pAccInfo | ) | [static, private] |
Definition at line 724 of file CAAccountingInstance.cpp.
References CAMutex::lock(), t_accountinginfo::mutex, setPrepaidBytesToZero_internal(), and CAMutex::unlock().
{
pAccInfo->mutex->lock();
setPrepaidBytesToZero_internal(pAccInfo);
pAccInfo->mutex->unlock();
}
| void CAAccountingInstance::setPrepaidBytesToZero_internal | ( | tAiAccountingInfo * | pAccInfo | ) | [inline, static, private] |
Definition at line 732 of file CAAccountingInstance.cpp.
References t_accountinginfo::confirmedBytes, and t_accountinginfo::transferredBytes.
Referenced by returnKickout(), and setPrepaidBytesToZero().
{
pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
}
| SINT32 CAAccountingInstance::settlementTransaction | ( | ) | [static] |
Definition at line 3290 of file CAAccountingInstance.cpp.
References SettleEntry::accountNumber, AUTH_ACCOUNT_EMPTY, AUTH_BLOCKED, AUTH_INVALID_ACCOUNT, AUTH_OUTDATED_CC, AUTH_SETTLED_ONCE, AUTH_UNKNOWN, AUTH_WAITING_FOR_FIRST_SETTLED_CC, AccountLoginHashEntry::authFlags, SettleEntry::authFlags, AccountLoginHashEntry::authRemoveFlags, SettleEntry::authRemoveFlags, BEGIN_STACK, CAAccountingDBInterface::clearAccountStatus(), AccountLoginHashEntry::confirmedBytes, SettleEntry::confirmedBytes, CRITICAL_SUBSEQUENT_BI_CONN_ERRORS, CAAccountingDBInterface::deleteCC(), SettleEntry::diffBytes, E_NOT_CONNECTED, E_SUCCESS, E_UNKNOWN, CAXMLErrorMessage::ERR_ACCOUNT_EMPTY, CAXMLErrorMessage::ERR_BLOCKED, CAXMLErrorMessage::ERR_DATABASE_ERROR, CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR, CAXMLErrorMessage::ERR_KEY_NOT_FOUND, CAXMLErrorMessage::ERR_OK, CAXMLErrorMessage::ERR_OUTDATED_CC, CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS, FINISH_STACK, CAXMLCostConfirmation::getAccountNumber(), CAAccountingDBInterface::getAccountStatus(), CAAccountingDBInterface::getConnection(), CAXMLErrorMessage::getDescription(), CAXMLErrorMessage::getErrorCode(), CAXMLErrorMessage::getMessageObject(), Hashtable::getMutex(), CAAccountingDBInterface::getPrepaidAmount(), CAXMLCostConfirmation::getTransferredBytes(), CAAccountingDBInterface::getUnsettledCostConfirmations(), Hashtable::getValue(), INIT_STACK, CAAccountingBIInterface::initBIConnection(), CAMutex::lock(), m_currentAccountsHashtable, m_currentCascade, m_nextSettleNr, m_pPiInterface, m_pSettlementMutex, m_seqBIConnErrors, m_settleWaitNr, CAAccountingDBInterface::markAsSettled(), MAX_SETTLED_CCS, MONITORING_FIRE_PAY_EVENT, ms_pInstance, SettleEntry::nextEntry, print64(), CAMsg::printMsg(), CAAccountingDBInterface::releaseConnection(), SAVE_STACK, CAAccountingBIInterface::settle(), CAConditionVariable::signal(), CAAccountingDBInterface::storeAccountStatus(), CAAccountingDBInterface::storeCostConfirmation(), SettleEntry::storedStatus, CAAccountingDBInterface::storePrepaidAmount(), CAAccountingBIInterface::terminateBIConnection(), CAMutex::unlock(), and CAConditionVariable::wait().
{
INIT_STACK;
BEGIN_STACK("CAAccountingInstance::settlementTransaction");
SINT32 ret = 0;
CAXMLErrorMessage * pErrMsg = NULL;
CAXMLCostConfirmation * pCC = NULL;
//CAQueue q;
CAXMLCostConfirmation **allUnsettledCCs = NULL;
UINT32 /*size, qSize, */ nrOfCCs, i;
SettleEntry *entry = NULL, *nextEntry = NULL;
CAAccountingDBInterface *dbInterface = NULL;
/* This should never happen */
if(ms_pInstance == NULL)
{
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return E_UNKNOWN;
}
/* This should never happen */
if(ms_pInstance->m_pSettlementMutex == NULL)
{
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return E_UNKNOWN;
}
//sleep(5);
dbInterface = CAAccountingDBInterface::getConnection();
if(dbInterface == NULL)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
//MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return E_NOT_CONNECTED;
}
//MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
ms_pInstance->m_pSettlementMutex->lock();
/* First part get unsettled CCs from the AI database */
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
#endif
dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
if (nrOfCCs <= 0)
{
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found no CCs to settle\n");
if(dbInterface != NULL)
{
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
ms_pInstance->m_pSettlementMutex->unlock();
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return E_SUCCESS;
}
//qSize = q.getSize();
//nrOfCCs = qSize / sizeof(pCC);
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found %u cost confirmations to settle\n",nrOfCCs);
SAVE_STACK("CAAccountingInstance::settlementTransaction", "After getting unsettled CCs");
/* Second part: We found unsettled CCs. Now contact the Payment Instance to settle them */
//while(!q.isEmpty())
for(i = 0; i < nrOfCCs; i++)
{
// get the next CC from the queue
/*size = sizeof(pCC);
ret = q.get((UINT8*)(&pCC), &size);
if(ret != E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not get next item from queue\n");
q.clean();
if(dbInterface != NULL)
{
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}
ms_pInstance->m_pSettlementMutex->unlock();
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return ret;
//break;
}*/
pCC = allUnsettledCCs[i];
entry = NULL;
nextEntry = NULL;
if (!pCC)
{
CAMsg::printMsg(LOG_CRIT, "Settlement transaction: Cost confirmation is NULL!\n");
continue;
}
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Connecting to payment instance...\n");
#endif
ret = ms_pInstance->m_pPiInterface->initBIConnection();
if(ret != E_SUCCESS)
{
ms_pInstance->m_seqBIConnErrors++;
if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
{
//transition to critical BI conn payment state
MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
}
else
{
MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
}
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: could not connect to BI. Try later...\n");
//q.clean();
pErrMsg = NULL; // continue in order to tell AUTH_WAITING_FOR_FIRST_SETTLED_CC for all accounts
ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
}
else
{
MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionSuccess);
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: successfully connected to payment instance");
#endif
ms_pInstance->m_seqBIConnErrors = 0;
pErrMsg = ms_pInstance->m_pPiInterface->settle( *pCC );
ms_pInstance->m_pPiInterface->terminateBIConnection();
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settle done!\n");
}
bool bDeleteCC = false;
UINT32 authFlags = 0;
UINT32 authRemoveFlags = 0;
UINT64 confirmedBytes = 0;
UINT64 diffBytes = 0;
UINT32 storedStatus = 0;
dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
// check returncode
if(pErrMsg == NULL) //no returncode -> connection error
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
}
else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK) //BI reported error
{
CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
pErrMsg->getErrorCode(), pErrMsg->getDescription() );
if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
{
authFlags |= AUTH_INVALID_ACCOUNT;
//dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
bDeleteCC = true;
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
authFlags |= AUTH_ACCOUNT_EMPTY;
UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
if (msgConfirmedBytes)
{
confirmedBytes = *msgConfirmedBytes;
if (confirmedBytes < pCC->getTransferredBytes())
{
diffBytes = pCC->getTransferredBytes() - confirmedBytes;
}
UINT8 tmp[32];
print64(tmp, confirmedBytes);
UINT8 tmp2[32];
print64(tmp2, diffBytes);
UINT8 tmp3[32];
print64(tmp3, pCC->getTransferredBytes());
CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
}
else
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Account empty, but no message object received! "
"This may lead to too much prepaid bytes!\n");
}
dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
authFlags |= AUTH_SETTLED_ONCE;
dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
pCC->getTransferredBytes());
//#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
pCC->getTransferredBytes(), pCC->getAccountNumber());
//#endif
}
/*
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
{
// this should never happen; the price certs in this CC do not fit to the ones of the cascade
// bDeleteCC = true;
}*/
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
//get attached CC from error message
CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
if (attachedCC)
{
authFlags |= AUTH_OUTDATED_CC;
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
//store it in DB
if (dbInterface->storeCostConfirmation(*attachedCC,
ms_pInstance->m_currentCascade) == E_SUCCESS)
{
authFlags |= AUTH_SETTLED_ONCE;
if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
attachedCC->getTransferredBytes()) != E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
"Maybe a new CC has been added meanwhile?\n");
}
}
else
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
}
// set the confirmed bytes to the value of the CC got from the PI
confirmedBytes = attachedCC->getTransferredBytes();
}
else
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
}
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
{
authFlags |= AUTH_BLOCKED;
bDeleteCC = true;
dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
{
//authFlags |= AUTH_DATABASE;
// the user is not responsible for this!
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
}
else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
{
// kick out the user and store the CC
authFlags |= AUTH_UNKNOWN;
}
else
{
// an unknown error leads to user kickout
CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
authFlags |= AUTH_UNKNOWN;
bDeleteCC = true;
}
if (bDeleteCC)
{
//delete costconfirmation to avoid trying to settle an unusable CC again and again
if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
}
else
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
}
}
}
else //settling was OK, so mark account as settled
{
authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
authFlags |= AUTH_SETTLED_ONCE;
if (dbInterface->markAsSettled(pCC->getAccountNumber(),
ms_pInstance->m_currentCascade,
pCC->getTransferredBytes()) != E_SUCCESS)
{
CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
}
CAMsg::printMsg(LOG_INFO, "Settlement transaction: CC OK!\n");
}
if (authFlags || authRemoveFlags)
{
nextEntry = new SettleEntry;
nextEntry->accountNumber = pCC->getAccountNumber();
nextEntry->authFlags = authFlags;
nextEntry->authRemoveFlags = authRemoveFlags;
nextEntry->confirmedBytes = confirmedBytes;
nextEntry->diffBytes = diffBytes;
nextEntry->nextEntry = entry;
nextEntry->storedStatus = storedStatus;
entry = nextEntry;
}
/*if (pCC != NULL)
{
delete pCC;
pCC = NULL;
}*/
if (pErrMsg != NULL)
{
delete pErrMsg;
pErrMsg = NULL;
}
}
if(allUnsettledCCs != NULL)
{
for(i = 0; i < nrOfCCs; i++)
{
delete allUnsettledCCs[i];
allUnsettledCCs[i] = NULL;
}
delete [] allUnsettledCCs;
allUnsettledCCs = NULL;
}
SAVE_STACK("CAAccountingInstance::settlementTransaction", "After settling unsettled CCs with BI");
SettleEntry *first = entry;
UINT64 myWaitNr = 0;
if (entry)
{
//wait numbers are used to obtain a synchronisation with FCFS assertion.
//This additional synchronisation is necessary because before acquiring the login hashtable
//locks the settlementMutex should be released. (Nested locking should be avoided).
if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
{
//CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
//no one is waiting, we use this occasion to reset the wait numbers
ms_pInstance->m_nextSettleNr = 0;
ms_pInstance->m_settleWaitNr = 1;
}
else
{
SAVE_STACK("CAAccountingInstance::settlementTransaction", "wait for altering hashtable");
//get global wait number and wait but release the DBConnection first.
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
myWaitNr = ms_pInstance->m_settleWaitNr;
ms_pInstance->m_settleWaitNr++;
while(myWaitNr != ms_pInstance->m_nextSettleNr)
{
CAMsg::printMsg(LOG_INFO, "Thread %x must wait to alter login table after settling (2): %llu before him in the queue\n", pthread_self(),
(myWaitNr - ms_pInstance->m_nextSettleNr));
ms_pInstance->m_pSettlementMutex->wait();
}
CAMsg::printMsg(LOG_INFO, "Thread %x may continue (2).\n", pthread_self());
dbInterface = CAAccountingDBInterface::getConnection();
}
SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering DB entries");
while (entry != NULL && dbInterface != NULL)
{
if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
{
dbInterface->storePrepaidAmount(
entry->accountNumber, 0, ms_pInstance->m_currentCascade);
}
else if (entry->diffBytes)
{
// user is currently not logged in; set correct prepaid bytes in DB
SINT32 prepaidBytes =
dbInterface->getPrepaidAmount(entry->accountNumber,
ms_pInstance->m_currentCascade, true);
if (prepaidBytes > 0)
{
if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
{
prepaidBytes = 0;
}
else
{
prepaidBytes -= entry->diffBytes;
}
dbInterface->storePrepaidAmount(
entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
}
}
if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
entry->storedStatus != 0)
{
dbInterface->clearAccountStatus(entry->accountNumber);
switch (entry->storedStatus)
{
case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
break;
}
case CAXMLErrorMessage::ERR_BLOCKED:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_BLOCKED;
break;
}
case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
{
CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
entry->accountNumber);
entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
break;
}
}
}
nextEntry = entry->nextEntry;
entry = nextEntry;
}
}
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
ms_pInstance->m_pSettlementMutex->unlock();
if(first != NULL)
{
SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering hashtable");
#ifdef DEBUG
CAMsg::printMsg(LOG_DEBUG, "Settlement thread with wait nr %llu alters hashtable.\n", myWaitNr);
#endif
entry = first;
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
while (entry != NULL)
{
AccountLoginHashEntry* loginEntry =
(AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
if (loginEntry)
{
// the user is currently logged in
loginEntry->authFlags |= entry->authFlags;
loginEntry->authRemoveFlags |= entry->authRemoveFlags;
if (entry->confirmedBytes > 0 &&
loginEntry->confirmedBytes < entry->confirmedBytes)
{
loginEntry->confirmedBytes = entry->confirmedBytes;
}
}
nextEntry = entry->nextEntry;
delete entry;
entry = nextEntry;
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
ms_pInstance->m_pSettlementMutex->lock();
ms_pInstance->m_nextSettleNr++;
// TODO: seems to be a bug; if this "if" is set, some locks are never released
//if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
{
SAVE_STACK("CAAccountingInstance::settlementTransaction", "waking up waiting threads for altering hashtable");
//There are threads waiting for applying their settlement results.
if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
CAMsg::printMsg(LOG_INFO, "Thread %x Waking up next Thread %llu are waiting.\n", pthread_self(),
(ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));
ms_pInstance->m_pSettlementMutex->signal();
}
ms_pInstance->m_pSettlementMutex->unlock();
}
/*if(dbInterface != NULL)
{
CAAccountingDBInterface::releaseConnection(dbInterface);
dbInterface = NULL;
}*/
FINISH_STACK("CAAccountingInstance::settlementTransaction");
return E_SUCCESS;
}
| UINT64 CAAccountingInstance::unlockLogin | ( | fmHashTableEntry * | ownerRef | ) | [static, private] |
release login (particularly for use in error case) this function is thread-safe.
Definition at line 3786 of file CAAccountingInstance.cpp.
References t_accountinginfo::accountNumber, Hashtable::getMutex(), Hashtable::getValue(), CAMutex::lock(), m_currentAccountsHashtable, ms_pInstance, t_fmhashtableentry::pAccountingInfo, resetLoginOngoing(), and CAMutex::unlock().
Referenced by CAFirstMix::doUserLogin_internal().
{
if(ownerRef == NULL || ownerRef->pAccountingInfo == NULL)
{
return 0;
}
UINT64 accountNumber = ownerRef->pAccountingInfo->accountNumber;
ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
AccountLoginHashEntry *loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
if (loginEntry != NULL)
{
resetLoginOngoing(loginEntry, ownerRef);
}
ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
return accountNumber;
}
friend class CAFirstMix [friend] |
Definition at line 115 of file CAAccountingInstance.hpp.
friend class CAFirstMixA [friend] |
Definition at line 114 of file CAAccountingInstance.hpp.
const SINT32 CAAccountingInstance::HANDLE_PACKET_CLOSE_CONNECTION = 3 [static] |
Definition at line 200 of file CAAccountingInstance.hpp.
Referenced by CAFirstMixA::accountTrafficDownstream(), CAFirstMixA::accountTrafficUpstream(), handleJapPacket_internal(), and returnKickout().
const SINT32 CAAccountingInstance::HANDLE_PACKET_CONNECTION_OK = 1 [static] |
Definition at line 196 of file CAAccountingInstance.hpp.
Referenced by CAFirstMixA::accountTrafficDownstream(), CAFirstMixA::accountTrafficUpstream(), and handleJapPacket_internal().
const SINT32 CAAccountingInstance::HANDLE_PACKET_CONNECTION_UNCHECKED = 4 [static] |
Definition at line 197 of file CAAccountingInstance.hpp.
Referenced by handleJapPacket_internal().
const SINT32 CAAccountingInstance::HANDLE_PACKET_HOLD_CONNECTION = 0 [static] |
Definition at line 198 of file CAAccountingInstance.hpp.
const SINT32 CAAccountingInstance::HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION = 2 [static] |
Definition at line 199 of file CAAccountingInstance.hpp.
Referenced by CAFirstMixA::accountTrafficDownstream(), CAFirstMixA::accountTrafficUpstream(), handleJapPacket_internal(), and returnPrepareKickout().
UINT8* CAAccountingInstance::m_AiName [private] |
the name of this accounting instance
Definition at line 289 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), and ~CAAccountingInstance().
CAThreadPool* CAAccountingInstance::m_aiThreadPool [private] |
reads messages from the queue and processes them
Definition at line 277 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), and ~CAAccountingInstance().
UINT8** CAAccountingInstance::m_allHashes [private] |
The hash values of the Mixes ordered beginning with the AI Mix.
Definition at line 297 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), prepareCCRequest(), and ~CAAccountingInstance().
UINT32 CAAccountingInstance::m_allHashesLen [private] |
Definition at line 298 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), cascadeMatchesCC(), handleCostConfirmation_internal(), prepareCCRequest(), and ~CAAccountingInstance().
bool CAAccountingInstance::m_bThreadRunning [private] |
Definition at line 331 of file CAAccountingInstance.hpp.
Hashtable* CAAccountingInstance::m_certHashCC [private] |
Definition at line 282 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), cascadeMatchesCC(), and ~CAAccountingInstance().
Stores the account number of all users currently logged in.
Definition at line 285 of file CAAccountingInstance.hpp.
Referenced by __commitSettlementToLoginTable(), __newSettlementTransaction(), CAAccountingInstance(), cleanupTableEntry(), finishLoginProcess(), getNrOfUsers(), handleChallengeResponse_internal(), handleJapPacket_internal(), settlementTransaction(), unlockLogin(), and ~CAAccountingInstance().
UINT8* CAAccountingInstance::m_currentCascade [private] |
current cascade (identified by the concatenated hash values of the price certificates)
Definition at line 294 of file CAAccountingInstance.hpp.
Referenced by __commitSettlementToDatabase(), __handleSettleResult(), __newSettlementTransaction(), CAAccountingInstance(), cleanupTableEntry(), handleAccountCertificate_internal(), handleChallengeResponse_internal(), handleCostConfirmation_internal(), handleJapPacket_internal(), prepareCCRequest(), settlementTransaction(), and ~CAAccountingInstance().
volatile UINT64 CAAccountingInstance::m_iCurrentSettleTransactionNr = 0 [static, private] |
Definition at line 342 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction().
Definition at line 305 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), and handleJapPacket_internal().
Definition at line 304 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), and handleJapPacket_internal().
CAFirstMix* CAAccountingInstance::m_mix [private] |
Definition at line 286 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), and handleChallengeResponse_internal().
volatile UINT64 CAAccountingInstance::m_nextSettleNr [private] |
Definition at line 336 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), CAAccountingInstance(), and settlementTransaction().
Users that get kicked out because they sent no authentication certificate get their IP appended to this list.
Connections from IP Addresses contained in this list get blocked, so that evil JAP users can't use the mix cascade without paying
Definition at line 313 of file CAAccountingInstance.hpp.
CAMutex* CAAccountingInstance::m_pMutex [private] |
this is for synchronizing the write access to the HashEntries
Definition at line 280 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), getNrOfUsers(), and ~CAAccountingInstance().
the interface to the database
Definition at line 302 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), CAAccountingInstance(), settlementTransaction(), and ~CAAccountingInstance().
SINT32 CAAccountingInstance::m_prepaidBytesMinimum = 0 [static, private] |
Definition at line 329 of file CAAccountingInstance.hpp.
XERCES_CPP_NAMESPACE::DOMDocument * CAAccountingInstance::m_preparedCCRequest [static, private] |
Definition at line 274 of file CAAccountingInstance.hpp.
Referenced by clean(), makeCCRequest(), makeInitialCCRequest(), and prepareCCRequest().
Definition at line 338 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), CAAccountingInstance(), settlementTransaction(), and ~CAAccountingInstance().
Signature verifying instance for BI signatures.
this thread sends cost confirmations to the BI in regular intervals
Definition at line 327 of file CAAccountingInstance.hpp.
Referenced by CAAccountingInstance(), handleCostConfirmation_internal(), and ~CAAccountingInstance().
volatile UINT32 CAAccountingInstance::m_seqBIConnErrors [private] |
Definition at line 340 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), CAAccountingInstance(), and settlementTransaction().
volatile UINT64 CAAccountingInstance::m_settleWaitNr [private] |
Definition at line 337 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), CAAccountingInstance(), and settlementTransaction().
const UINT32 CAAccountingInstance::MAX_SETTLED_CCS = 10 [static] |
Definition at line 203 of file CAAccountingInstance.hpp.
Referenced by __newSettlementTransaction(), newSettlementTransaction(), and settlementTransaction().
const UINT32 CAAccountingInstance::MAX_TOLERATED_MULTIPLE_LOGINS = 10 [static, private] |
Definition at line 272 of file CAAccountingInstance.hpp.
CAAccountingInstance * CAAccountingInstance::ms_pInstance = NULL [static, private] |
Singleton: This is the reference to the only instance of this class.
Definition at line 318 of file CAAccountingInstance.hpp.
Referenced by __commitSettlementToDatabase(), __commitSettlementToLoginTable(), __handleSettleResult(), __newSettlementTransaction(), clean(), cleanupTableEntry(), finishLoginProcess(), getNrOfUsers(), handleChallengeResponse_internal(), handleJapPacket_internal(), init(), processJapMessage(), processThread(), settlementTransaction(), and unlockLogin().
const UINT64 CAAccountingInstance::PACKETS_BEFORE_NEXT_CHECK = 100 [static, private] |
Definition at line 270 of file CAAccountingInstance.hpp.
Referenced by handleJapPacket_internal().
1.7.6.1