00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "StdAfx.h"
00029 #ifdef PAYMENT
00030 #include "CAAccountingDBInterface.hpp"
00031 #include "CACmdLnOptions.hpp"
00032 #include "CAXMLErrorMessage.hpp"
00033 #include "CAMsg.hpp"
00034 #include "CAStatusManager.hpp"
00035 #include "CALibProxytest.hpp"
00036
00037 CAConditionVariable *CAAccountingDBInterface::ms_pConnectionAvailable = NULL;
00038 volatile UINT64 CAAccountingDBInterface::ms_threadWaitNr = 0;
00039 volatile UINT64 CAAccountingDBInterface::ms_nextThreadNr = 0;
00040 CAAccountingDBInterface *CAAccountingDBInterface::ms_pDBConnectionPool[MAX_DB_CONNECTIONS];
00041
00045 CAAccountingDBInterface::CAAccountingDBInterface()
00046 {
00047 m_bConnected = false;
00048 m_dbConn=NULL;
00049 m_owner = 0;
00050
00051
00052
00053 m_free = true;
00054
00055 m_pConnectionMutex = new CAMutex();
00056 }
00057
00058
00062 CAAccountingDBInterface::~CAAccountingDBInterface()
00063 {
00064 terminateDBConnection();
00065 delete m_pConnectionMutex;
00066 m_pConnectionMutex = NULL;
00067 }
00068
00069
00078 SINT32 CAAccountingDBInterface::initDBConnection()
00079 {
00080 if(m_bConnected)
00081 {
00082 return E_UNKNOWN;
00083 }
00084
00085
00086 UINT8 host[255];
00087 if(CALibProxytest::getOptions()->getDatabaseHost(host, 255) != E_SUCCESS)
00088 {
00089 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Host!\n");
00090 return E_UNKNOWN;
00091 }
00092 UINT32 tcp_port = CALibProxytest::getOptions()->getDatabasePort();
00093 UINT8 dbName[255];
00094 if(CALibProxytest::getOptions()->getDatabaseName(dbName, 255) != E_SUCCESS)
00095 {
00096 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Name!\n");
00097 return E_UNKNOWN;
00098 }
00099 UINT8 userName[255];
00100 if(CALibProxytest::getOptions()->getDatabaseUsername(userName, 255) != E_SUCCESS)
00101 {
00102 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Username!\n");
00103 return E_UNKNOWN;
00104 }
00105 UINT8 password[255];
00106 if(CALibProxytest::getOptions()->getDatabasePassword(password, 255) != E_SUCCESS)
00107 {
00108 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Password!\n");
00109 return E_UNKNOWN;
00110 }
00111
00112
00113 char port[20];
00114 sprintf(port, "%i", tcp_port);
00115 m_dbConn = PQsetdbLogin(
00116 (char*)host, port, "", "",
00117 (char*)dbName, (char*)userName, (char*)password
00118 );
00119 if(m_dbConn==NULL||PQstatus(m_dbConn) == CONNECTION_BAD)
00120 {
00121 CAMsg::printMsg(
00122 LOG_ERR, "CAAccountingDBInterface: Could not connect to Database. Reason: %s\n",
00123 PQerrorMessage(m_dbConn)
00124 );
00125 PQfinish(m_dbConn);
00126 m_dbConn = NULL;
00127 m_bConnected = false;
00128 return E_NOT_CONNECTED;
00129 }
00130 m_bConnected = true;
00131 return E_SUCCESS;
00132 }
00133
00134 bool CAAccountingDBInterface::checkConnectionStatus()
00135 {
00136 if (!m_bConnected)
00137 {
00138 return false;
00139 }
00140
00141 if (PQstatus(m_dbConn) != CONNECTION_OK)
00142 {
00143 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Connection to database lost! Reason: %s\n",
00144 PQerrorMessage(m_dbConn));
00145 PQreset(m_dbConn);
00146
00147 if (PQstatus(m_dbConn) != CONNECTION_OK)
00148 {
00149 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not reset database connection! Reason: %s\n",
00150 PQerrorMessage(m_dbConn));
00151 terminateDBConnection();
00152 }
00153 else
00154 {
00155 CAMsg::printMsg(LOG_INFO, "CAAccountingDBInterface: Database connection has been reset successfully!");
00156 }
00157 }
00158 return m_bConnected;
00159 }
00160
00161 bool CAAccountingDBInterface::isDBConnected()
00162 {
00163 return m_bConnected;
00164 }
00165
00170 SINT32 CAAccountingDBInterface::terminateDBConnection()
00171 {
00172 if(m_bConnected)
00173 {
00174 PQfinish(m_dbConn);
00175 }
00176 m_dbConn=NULL;
00177 m_bConnected = false;
00178 return E_SUCCESS;
00179 }
00180
00181
00182 bool CAAccountingDBInterface::checkOwner()
00183 {
00184 bool isFree = false;
00185 thread_id_t owner = 0;
00186 m_pConnectionMutex->lock();
00187 owner = m_owner;
00188 isFree = m_free;
00189 m_pConnectionMutex->unlock();
00190
00191 return ( (owner==CAThread::getSelfID()) && !isFree);
00192 }
00193
00194
00195 SINT32 CAAccountingDBInterface::getCostConfirmation(UINT64 accountNumber, UINT8* cascadeId, CAXMLCostConfirmation **pCC, bool& a_bSettled)
00196 {
00197 if(checkOwner())
00198 {
00199 return __getCostConfirmation(accountNumber, cascadeId, pCC, a_bSettled);
00200 }
00201 else
00202 {
00203 return E_UNKNOWN;
00204 }
00205 }
00218 SINT32 CAAccountingDBInterface::__getCostConfirmation(UINT64 accountNumber, UINT8* cascadeId, CAXMLCostConfirmation **pCC, bool& a_bSettled)
00219 {
00220 if(!checkConnectionStatus())
00221 {
00222
00223
00224
00225 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00226 return E_NOT_CONNECTED;
00227 }
00228
00229 const char* queryF = "SELECT XMLCC, SETTLED FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
00230 UINT8* query;
00231 UINT8* xmlCC;
00232 PGresult* result;
00233 UINT8 tmp[32];
00234 print64(tmp,accountNumber);
00235
00236 query = new UINT8[strlen(queryF) + 32 + strlen((char*)cascadeId)];
00237 sprintf( (char *)query, queryF, tmp, cascadeId);
00238 #ifdef DEBUG
00239 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: executing query %s\n", query);
00240 #endif
00241
00242 result = monitored_PQexec(m_dbConn, (char *)query);
00243
00244 delete[] query;
00245 query = NULL;
00246 if(PQresultStatus(result)!=PGRES_TUPLES_OK)
00247 {
00248 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not read XMLCC. Reason: %s\n",
00249 PQresultErrorMessage(result));
00250 PQclear(result);
00251 return E_UNKNOWN;
00252 }
00253
00254 if(PQntuples(result)!=1)
00255 {
00256 #ifdef DEBUG
00257 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: XMLCC not found.\n");
00258 #endif
00259 PQclear(result);
00260 return E_NOT_FOUND;
00261 }
00262
00263 xmlCC = (UINT8*) PQgetvalue(result, 0, 0);
00264 if (atoi(PQgetvalue(result, 0, 1)) == 0)
00265 {
00266 a_bSettled = false;
00267 }
00268 else
00269 {
00270 a_bSettled = true;
00271 }
00272
00273 *pCC = CAXMLCostConfirmation::getInstance(xmlCC,strlen((char*)xmlCC));
00274 PQclear(result);
00275
00276 if(*pCC==NULL)
00277 {
00278 return E_UNKNOWN;
00279 }
00280 return E_SUCCESS;
00281 }
00282
00283 SINT32 CAAccountingDBInterface::checkCountAllQuery(UINT8* a_query, UINT32& r_count)
00284 {
00285 if(checkOwner())
00286 {
00287 return __checkCountAllQuery(a_query, r_count);
00288 }
00289 else
00290 {
00291 return E_UNKNOWN;
00292 }
00293 }
00294
00295 SINT32 CAAccountingDBInterface::__checkCountAllQuery(UINT8* a_query, UINT32& r_count)
00296 {
00297 r_count = 0;
00298
00299 if (!a_query)
00300 {
00301 return E_UNKNOWN;
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311 PGresult * pResult = monitored_PQexec(m_dbConn, (char*)a_query);
00312
00313 if(PQresultStatus(pResult) != PGRES_TUPLES_OK)
00314 {
00315 CAMsg::printMsg(LOG_ERR,
00316 "CAAccountingDBInterface: Database Error '%s' while processing query '%s'\n",
00317 PQresultErrorMessage(pResult), a_query
00318 );
00319 PQclear(pResult);
00320 return E_UNKNOWN;
00321 }
00322
00323 if ( (PQntuples(pResult) != 1) || (PQgetisnull(pResult, 0, 0)))
00324 {
00325 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Wrong number of tuples or null value\n");
00326 PQclear(pResult);
00327 return E_UNKNOWN;
00328 }
00329
00330 r_count = atoi(PQgetvalue(pResult, 0, 0));
00331 PQclear(pResult);
00332 return E_SUCCESS;
00333 }
00334
00335
00336
00337 SINT32 CAAccountingDBInterface::storeCostConfirmation(CAXMLCostConfirmation &cc, UINT8* ccCascade)
00338 {
00339 if(checkOwner())
00340 {
00341 return __storeCostConfirmation(cc, ccCascade);
00342 }
00343 else
00344 {
00345 return E_UNKNOWN;
00346 }
00347 }
00352 SINT32 CAAccountingDBInterface::__storeCostConfirmation( CAXMLCostConfirmation &cc, UINT8* ccCascade )
00353 {
00354 #ifndef HAVE_NATIVE_UINT64
00355 #warning Native UINT64 type not available - CostConfirmation Database might be non-functional
00356 #endif
00357 const char* previousCCQuery = "SELECT COUNT(*) FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER='%s' AND CASCADE='%s'";
00358 const char* query2F = "INSERT INTO COSTCONFIRMATIONS(BYTES, XMLCC, SETTLED, ACCOUNTNUMBER, CASCADE) VALUES ('%s', '%s', '%d', '%s', '%s')";
00359 const char* query3F = "UPDATE COSTCONFIRMATIONS SET BYTES='%s', XMLCC='%s', SETTLED='%d' WHERE ACCOUNTNUMBER='%s' AND CASCADE='%s'";
00360 const char* tempQuery;
00361
00362 UINT8 * query;
00363 UINT8 * pStrCC;
00364 UINT32 size;
00365 UINT32 len;
00366 UINT32 count;
00367 PGresult * pResult;
00368 UINT8 strAccountNumber[32];
00369 UINT8 tmp[32];
00370
00371 if(!checkConnectionStatus())
00372 {
00373 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00374 return E_NOT_CONNECTED;
00375 }
00376 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00377
00378 pStrCC = new UINT8[8192];
00379 size=8192;
00380 if(cc.toXMLString(pStrCC, &size)!=E_SUCCESS)
00381 {
00382 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstanceDBInterface: Could not transform CC to XML string!\n");
00383 delete[] pStrCC;
00384 pStrCC = NULL;
00385 return E_UNKNOWN;
00386 }
00387
00388 #ifdef DEBUG
00389 CAMsg::printMsg(LOG_DEBUG, "cc to store in db:%s\n",pStrCC);
00390 #endif
00391
00392
00393 len = max(strlen(previousCCQuery), strlen(query2F));
00394 len = max(len, strlen(query3F));
00395 query = new UINT8[len + 32 + 32 + 1 + size + strlen((char*)ccCascade)];
00396 print64(strAccountNumber,cc.getAccountNumber());
00397 sprintf( (char*)query, previousCCQuery, strAccountNumber, ccCascade);
00398
00399
00400 if (__checkCountAllQuery(query, count) != E_SUCCESS)
00401 {
00402 delete[] pStrCC;
00403 pStrCC = NULL;
00404 delete[] query;
00405 query = NULL;
00406 return E_UNKNOWN;
00407 }
00408
00409
00410 print64(tmp,cc.getTransferredBytes());
00411 if(count == 0)
00412 {
00413 tempQuery = query2F;
00414 }
00415 else
00416 {
00417 tempQuery = query3F;
00418 }
00419 sprintf((char*)query, tempQuery, tmp, pStrCC, 0, strAccountNumber, ccCascade);
00420
00421
00422 pResult = monitored_PQexec(m_dbConn, (char*)query);
00423
00424 delete[] pStrCC;
00425 pStrCC = NULL;
00426 if(PQresultStatus(pResult) != PGRES_COMMAND_OK)
00427 {
00428 CAMsg::printMsg(LOG_ERR, "Could not store CC!\n");
00429
00430 {
00431 CAMsg::printMsg(LOG_ERR,
00432 "Database message '%s' while processing query '%s'\n",
00433 PQresultErrorMessage(pResult), query
00434 );
00435 }
00436 delete[] query;
00437 query = NULL;
00438 PQclear(pResult);
00439 return E_UNKNOWN;
00440 }
00441 delete[] query;
00442 query = NULL;
00443 PQclear(pResult);
00444
00445 #ifdef DEBUG
00446 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstanceDBInterface: Finished storing CC in DB.\n");
00447 #endif
00448 return E_SUCCESS;
00449 }
00450
00451
00452 SINT32 CAAccountingDBInterface::getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8* cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
00453 {
00454 if(checkOwner())
00455 {
00456 return __getUnsettledCostConfirmations(resultCCs, cascadeId, nrOfCCs, a_maxCCs);
00457 }
00458 else
00459 {
00460 return E_UNKNOWN;
00461 }
00462 }
00471 SINT32 CAAccountingDBInterface::__getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8* cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
00472 {
00473 const char* query= "SELECT XMLCC FROM COSTCONFIRMATIONS WHERE SETTLED=0 AND CASCADE = '%s' LIMIT %u";
00474 UINT8* finalQuery;
00475 PGresult* result;
00476 SINT32 numTuples, i;
00477 UINT8* pTmpStr;
00478 CAXMLCostConfirmation* pCC;
00479
00480 if(!checkConnectionStatus())
00481 {
00482 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00483 return E_NOT_CONNECTED;
00484 }
00485 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00486
00487 finalQuery = new UINT8[strlen(query)+strlen((char*)cascadeId)];
00488 sprintf( (char*)finalQuery, query, cascadeId, a_maxCCs);
00489
00490 #ifdef DEBUG
00491 CAMsg::printMsg(LOG_DEBUG, "Getting Cost confirmations for cascade: ");
00492 CAMsg::printMsg(LOG_DEBUG, (const char*) finalQuery);
00493 #endif
00494
00495 result = monitored_PQexec(m_dbConn, (char *)finalQuery);
00496
00497 delete[] finalQuery;
00498 finalQuery = NULL;
00499 if(PQresultStatus(result) != PGRES_TUPLES_OK)
00500 {
00501 PQclear(result);
00502 return E_UNKNOWN;
00503 }
00504 numTuples = PQntuples(result);
00505 *nrOfCCs = numTuples;
00506
00507 if(numTuples > 0)
00508 {
00509
00510 *resultCCs = new CAXMLCostConfirmation *[numTuples];
00511 i = 0;
00512 while(i < *nrOfCCs)
00513 {
00514 pTmpStr = (UINT8*) PQgetvalue(result, i, 0);
00515 if( (pTmpStr!=NULL)&&
00516 ( (pCC = CAXMLCostConfirmation::getInstance(pTmpStr,strlen((char*)pTmpStr)) )!=NULL))
00517 {
00518 (*resultCCs)[i] = pCC;
00519 i++;
00520 }
00521 else
00522 {
00523
00524
00525 (*nrOfCCs)--;
00526 }
00527 }
00528 }
00529 PQclear(result);
00530
00531
00532 return E_SUCCESS;
00533 }
00534
00535 SINT32 CAAccountingDBInterface::markAsSettled(UINT64 accountNumber, UINT8* cascadeId, UINT64 a_transferredBytes)
00536 {
00537 if(checkOwner())
00538 {
00539 return __markAsSettled(accountNumber, cascadeId, a_transferredBytes);
00540 }
00541 else
00542 {
00543 return E_UNKNOWN;
00544 }
00545 }
00552 SINT32 CAAccountingDBInterface::__markAsSettled(UINT64 accountNumber, UINT8* cascadeId, UINT64 a_transferredBytes)
00553 {
00554 const char* queryF = "UPDATE COSTCONFIRMATIONS SET SETTLED=1 WHERE ACCOUNTNUMBER=%s AND BYTES=%s AND CASCADE='%s'";
00555 UINT8 * query;
00556 PGresult * result;
00557
00558 if(!checkConnectionStatus())
00559 {
00560 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00561 return E_NOT_CONNECTED;
00562 }
00563 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00564
00565 UINT8 tmp[32], tmp2[32];
00566 print64(tmp,accountNumber);
00567 print64(tmp2,a_transferredBytes);
00568 query = new UINT8[strlen(queryF) + 32 + 32 + strlen((char*)cascadeId)];
00569 sprintf((char *)query, queryF, tmp, tmp2, cascadeId);
00570 result = monitored_PQexec(m_dbConn, (char *)query);
00571
00572 delete[] query;
00573 query = NULL;
00574 if(PQresultStatus(result) != PGRES_COMMAND_OK)
00575 {
00576 PQclear(result);
00577 return E_UNKNOWN;
00578 }
00579 PQclear(result);
00580
00581 return E_SUCCESS;
00582 }
00583
00584 SINT32 CAAccountingDBInterface::deleteCC(UINT64 accountNumber, UINT8* cascadeId)
00585 {
00586 if(checkOwner())
00587 {
00588 return __deleteCC(accountNumber, cascadeId);
00589 }
00590 else
00591 {
00592 return E_UNKNOWN;
00593 }
00594 }
00595
00596 SINT32 CAAccountingDBInterface::__deleteCC(UINT64 accountNumber, UINT8* cascadeId)
00597 {
00598 const char* deleteQuery = "DELETE FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER = %s AND CASCADE='%s'";
00599 UINT8* finalQuery;
00600 PGresult* result;
00601 SINT32 ret;
00602 UINT8 temp[32];
00603 print64(temp,accountNumber);
00604
00605 if (!checkConnectionStatus())
00606 {
00607 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00608 ret = E_NOT_CONNECTED;
00609 }
00610 else
00611 {
00612 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00613
00614 finalQuery = new UINT8[strlen(deleteQuery)+ 32 + strlen((char*)cascadeId)];
00615 sprintf((char *)finalQuery,deleteQuery,temp, cascadeId);
00616 result = monitored_PQexec(m_dbConn, (char*)finalQuery);
00617
00618
00619 delete[] finalQuery;
00620 finalQuery = NULL;
00621 if (PQresultStatus(result) != PGRES_COMMAND_OK)
00622 {
00623 PQclear(result);
00624 ret = E_UNKNOWN;
00625 }
00626 else
00627 {
00628 PQclear(result);
00629 ret = E_SUCCESS;
00630 }
00631 }
00632
00633 if (ret == E_SUCCESS)
00634 {
00635 CAMsg::printMsg(LOG_INFO, "CAAccountingDBInterface: Costconfirmation for account %s was deleted!\n", temp);
00636 }
00637 else
00638 {
00639 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not delete account %s!\n", temp);
00640 }
00641
00642 return ret;
00643 }
00644
00645 SINT32 CAAccountingDBInterface::storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8* cascadeId)
00646 {
00647 if(checkOwner())
00648 {
00649 return __storePrepaidAmount(accountNumber, prepaidBytes, cascadeId);
00650 }
00651 else
00652 {
00653 return E_UNKNOWN;
00654 }
00655 }
00656
00657
00658
00659 SINT32 CAAccountingDBInterface::__storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8* cascadeId)
00660 {
00661 const char* selectQuery = "SELECT COUNT(*) FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
00662 const char* insertQuery = "INSERT INTO PREPAIDAMOUNTS(PREPAIDBYTES, ACCOUNTNUMBER, CASCADE) VALUES (%d, %s, '%s')";
00663 const char* updateQuery = "UPDATE PREPAIDAMOUNTS SET PREPAIDBYTES=%d WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
00664
00665 const char* query;
00666
00667 PGresult* result;
00668 UINT8* finalQuery;
00669 UINT8 tmp[32];
00670 UINT32 len;
00671 UINT32 count;
00672 print64(tmp,accountNumber);
00673
00674 if(!checkConnectionStatus())
00675 {
00676 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00677 return E_NOT_CONNECTED;
00678 }
00679
00680 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00681
00682 len = max(strlen(selectQuery), strlen(insertQuery));
00683 len = max(len, strlen(updateQuery));
00684 finalQuery = new UINT8[len + 32 + 32 + strlen((char*)cascadeId)];
00685 sprintf( (char *)finalQuery, selectQuery, tmp, cascadeId);
00686
00687 if (__checkCountAllQuery(finalQuery, count) != E_SUCCESS)
00688 {
00689 delete[] finalQuery;
00690 finalQuery = NULL;
00691
00692
00693
00694
00695
00696 return E_UNKNOWN;
00697 }
00698
00699
00700 if(count == 0)
00701 {
00702 query = insertQuery;
00703 }
00704 else
00705 {
00706 query = updateQuery;
00707 }
00708 sprintf((char*)finalQuery, query, prepaidBytes, tmp, cascadeId);
00709 result = monitored_PQexec(m_dbConn, (char *)finalQuery);
00710
00711 if (PQresultStatus(result) != PGRES_COMMAND_OK)
00712 {
00713 CAMsg::printMsg(LOG_ERR, "CAAccountungDBInterface: Saving to prepaidamounts failed!\n");
00714
00715 {
00716 CAMsg::printMsg(LOG_ERR,
00717 "Database message '%s' while processing query '%s'\n",
00718 PQresultErrorMessage(result), finalQuery
00719 );
00720 }
00721 delete[] finalQuery;
00722 finalQuery = NULL;
00723 if (result)
00724 {
00725 PQclear(result);
00726 }
00727 return E_UNKNOWN;
00728 }
00729 delete[] finalQuery;
00730 finalQuery = NULL;
00731 PQclear(result);
00732 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Stored %d prepaid bytes for account nr. %s \n",prepaidBytes, tmp);
00733 return E_SUCCESS;
00734 }
00735
00736 SINT32 CAAccountingDBInterface::getPrepaidAmount(UINT64 accountNumber, UINT8* cascadeId, bool a_bDelete)
00737 {
00738 if(checkOwner())
00739 {
00740 return __getPrepaidAmount(accountNumber, cascadeId, a_bDelete);
00741 }
00742 else
00743 {
00744 return E_UNKNOWN;
00745 }
00746 }
00747
00748
00749
00750
00751
00752
00753 SINT32 CAAccountingDBInterface::__getPrepaidAmount(UINT64 accountNumber, UINT8* cascadeId, bool a_bDelete)
00754 {
00755
00756 const char* selectQuery = "SELECT PREPAIDBYTES FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
00757 PGresult* result;
00758 UINT8* finalQuery;
00759 UINT8 accountNumberAsString[32];
00760 print64(accountNumberAsString,accountNumber);
00761
00762 if(!checkConnectionStatus())
00763 {
00764 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00765 return E_NOT_CONNECTED;
00766 }
00767 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00768
00769 finalQuery = new UINT8[strlen(selectQuery) + 32 + strlen((char*)cascadeId)];
00770 sprintf( (char *)finalQuery, selectQuery, accountNumberAsString, cascadeId);
00771 result = monitored_PQexec(m_dbConn, (char *)finalQuery);
00772
00773 if(PQresultStatus(result)!=PGRES_TUPLES_OK)
00774 {
00775 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Database error while trying to read prepaid bytes, Reason: %s\n", PQresultErrorMessage(result));
00776 PQclear(result);
00777 delete[] finalQuery;
00778 finalQuery = NULL;
00779 return E_UNKNOWN;
00780 }
00781
00782 if(PQntuples(result)!=1)
00783 {
00784
00785 PQclear(result);
00786 delete[] finalQuery;
00787 finalQuery = NULL;
00788 return 0;
00789 }
00790 SINT32 nrOfBytes = atoi(PQgetvalue(result, 0, 0));
00791 PQclear(result);
00792
00793 if (a_bDelete)
00794 {
00795
00796 const char* deleteQuery = "DELETE FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s' ";
00797 PGresult* result2;
00798 print64(accountNumberAsString,accountNumber);
00799 sprintf( (char *)finalQuery, deleteQuery, accountNumberAsString, cascadeId);
00800
00801 result2 = monitored_PQexec(m_dbConn, (char *)finalQuery);
00802
00803 if (PQresultStatus(result2) != PGRES_COMMAND_OK)
00804 {
00805 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Deleting read prepaidamount failed.");
00806 }
00807 PQclear(result2);
00808 }
00809
00810 delete[] finalQuery;
00811 finalQuery = NULL;
00812
00813 return nrOfBytes;
00814 }
00815
00816 SINT32 CAAccountingDBInterface::storeAccountStatus(UINT64 a_accountNumber, UINT32 a_statusCode)
00817 {
00818 if(checkOwner())
00819 {
00820 return __storeAccountStatus(a_accountNumber, a_statusCode);
00821 }
00822 else
00823 {
00824 return E_UNKNOWN;
00825 }
00826 }
00827
00828
00829
00830 SINT32 CAAccountingDBInterface::__storeAccountStatus(UINT64 accountNumber, UINT32 statuscode)
00831 {
00832 const char* previousStatusQuery = "SELECT COUNT(*) FROM ACCOUNTSTATUS WHERE ACCOUNTNUMBER='%s' ";
00833
00834 const char* insertQuery = "INSERT INTO ACCOUNTSTATUS(STATUSCODE,ACCOUNTNUMBER) VALUES ('%u', '%s')";
00835 const char* updateQuery = "UPDATE ACCOUNTSTATUS SET STATUSCODE=%u WHERE ACCOUNTNUMBER=%s";
00836 const char* query;
00837
00838 PGresult* result;
00839 UINT8* finalQuery;
00840 UINT8 tmp[32];
00841 UINT32 len;
00842 UINT32 count;
00843 print64(tmp,accountNumber);
00844
00845 if(!checkConnectionStatus())
00846 {
00847 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00848 return E_NOT_CONNECTED;
00849 }
00850 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00851
00852 len = max(strlen(previousStatusQuery), strlen(insertQuery));
00853 len = max(len, strlen(updateQuery));
00854 finalQuery = new UINT8[len + 32 + 32 + 32];
00855 sprintf( (char *)finalQuery, previousStatusQuery, tmp);
00856
00857 if (__checkCountAllQuery(finalQuery, count) != E_SUCCESS)
00858 {
00859 delete[] finalQuery;
00860 finalQuery = NULL;
00861 return E_UNKNOWN;
00862 }
00863
00864
00865 if(count == 0)
00866 {
00867 query = insertQuery;
00868 }
00869 else
00870 {
00871 query = updateQuery;
00872 }
00873 sprintf((char*)finalQuery, query, statuscode, tmp);
00874 result = monitored_PQexec(m_dbConn, (char *)finalQuery);
00875
00876 if (PQresultStatus(result) != PGRES_COMMAND_OK)
00877 {
00878 CAMsg::printMsg(LOG_ERR, "CAAccountungDBInterface: Saving the account status failed!\n");
00879
00880 {
00881 CAMsg::printMsg(LOG_ERR,
00882 "Database Error '%s' while processing query '%s'\n",
00883 PQresultErrorMessage(result), finalQuery
00884 );
00885 }
00886 delete[] finalQuery;
00887 finalQuery = NULL;
00888 if (result)
00889 {
00890 PQclear(result);
00891 }
00892 return E_UNKNOWN;
00893 }
00894 delete[] finalQuery;
00895 finalQuery = NULL;
00896 PQclear(result);
00897 CAMsg::printMsg(LOG_DEBUG, "Stored status code %u for account nr. %s \n",statuscode, tmp);
00898 return E_SUCCESS;
00899 }
00900
00901 SINT32 CAAccountingDBInterface::clearAccountStatus(UINT64 a_accountNumber)
00902 {
00903 if(checkOwner())
00904 {
00905 return __clearAccountStatus(a_accountNumber);
00906 }
00907 else
00908 {
00909 return E_UNKNOWN;
00910 }
00911 }
00912
00913 SINT32 CAAccountingDBInterface::__clearAccountStatus(UINT64 a_accountNumber)
00914 {
00915 SINT32 ret = E_SUCCESS;
00916 PGresult* result = NULL;
00917 size_t queryMaxLen = strlen(STMT_CLEAR_ACCOUNT_STATUS) + ACCOUNT_NUMBER_SIZE;
00918 char* clearAccountStatusStmt=new char[queryMaxLen+1];
00919 memset(clearAccountStatusStmt, 0, queryMaxLen+1);
00920
00921 if( (a_accountNumber > MAX_ACCOUNTNUMBER) &&
00922 (a_accountNumber < MIN_ACCOUNTNUMBER) )
00923 {
00924 CAMsg::printMsg(LOG_DEBUG, "Cannot clear account status: accountnumber &llu is invalid.\n",
00925 a_accountNumber);
00926 delete[] clearAccountStatusStmt;
00927 return E_UNKNOWN;
00928 }
00929 snprintf(clearAccountStatusStmt, queryMaxLen, STMT_CLEAR_ACCOUNT_STATUS, a_accountNumber);
00930 result = monitored_PQexec(m_dbConn, clearAccountStatusStmt);
00931 if(result != NULL)
00932 {
00933 if (PQresultStatus(result) != PGRES_COMMAND_OK)
00934 {
00935 CAMsg::printMsg(LOG_DEBUG, "Clearing accountstatus for account %llu failed.\n", a_accountNumber);
00936 ret = E_UNKNOWN;
00937 }
00938 PQclear(result);
00939 delete[] clearAccountStatusStmt;
00940 return ret;
00941 }
00942 delete[] clearAccountStatusStmt;
00943 CAMsg::printMsg(LOG_DEBUG, "Clearing accountstatus for account %llu failed.\n", a_accountNumber);
00944 return E_UNKNOWN;
00945 }
00946
00947 SINT32 CAAccountingDBInterface::getAccountStatus(UINT64 a_accountNumber, UINT32& a_statusCode)
00948 {
00949 if(checkOwner())
00950 {
00951 return __getAccountStatus(a_accountNumber, a_statusCode);
00952 }
00953 else
00954 {
00955 return E_UNKNOWN;
00956 }
00957 }
00958
00959
00960
00961
00962 SINT32 CAAccountingDBInterface::__getAccountStatus(UINT64 accountNumber, UINT32& a_statusCode)
00963 {
00964 const char* selectQuery = "SELECT STATUSCODE FROM ACCOUNTSTATUS WHERE ACCOUNTNUMBER = %s";
00965 PGresult* result;
00966 UINT8* finalQuery;
00967 UINT8 accountNumberAsString[32];
00968 print64(accountNumberAsString,accountNumber);
00969
00970 if(!checkConnectionStatus())
00971 {
00972 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
00973 return E_NOT_CONNECTED;
00974 }
00975 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
00976
00977 a_statusCode = CAXMLErrorMessage::ERR_OK;
00978
00979 finalQuery = new UINT8[strlen(selectQuery) + 32];
00980 sprintf( (char *)finalQuery, selectQuery, accountNumberAsString);
00981 result = monitored_PQexec(m_dbConn, (char *)finalQuery);
00982
00983 delete[] finalQuery;
00984 finalQuery = NULL;
00985 if(PQresultStatus(result)!=PGRES_TUPLES_OK)
00986 {
00987 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Database error while trying to read account status, Reason: %s\n", PQresultErrorMessage(result));
00988 PQclear(result);
00989 return E_UNKNOWN;
00990 }
00991
00992 if(PQntuples(result) == 1)
00993 {
00994 int statusCodeIndex = PQfnumber(result,"STATUSCODE");
00995
00996 if(statusCodeIndex != -1 )
00997 {
00998 a_statusCode = atoi(PQgetvalue(result, 0, statusCodeIndex));
00999 }
01000 else
01001 {
01002 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: no status code found while reading account status\n");
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 }
01014
01015 PQclear(result);
01016
01017 return E_SUCCESS;
01018 }
01019
01020 CAAccountingDBInterface *CAAccountingDBInterface::getConnection()
01021 {
01022 UINT32 i;
01023 UINT64 myWaitNr;
01024 CAAccountingDBInterface *returnedConnection = NULL;
01025
01026 if(ms_pDBConnectionPool == NULL)
01027 {
01028 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: No DBConnection available. This should NEVER happen!\n");
01029 return NULL;
01030 }
01031 if(ms_pConnectionAvailable == NULL)
01032 {
01033 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnections not initialized. This should NEVER happen!\n");
01034 return NULL;
01035 }
01036 ms_pConnectionAvailable->lock();
01037 for(i=0; 1; i++)
01038 {
01039 if(ms_pDBConnectionPool[(i%MAX_DB_CONNECTIONS)] != NULL)
01040 {
01041 if(ms_pDBConnectionPool[(i%MAX_DB_CONNECTIONS)]->testAndSetOwner())
01042 {
01043 returnedConnection = ms_pDBConnectionPool[(i%MAX_DB_CONNECTIONS)];
01044 break;
01045 }
01046 }
01047 if((i % MAX_DB_CONNECTIONS) == (MAX_DB_CONNECTIONS - 1) )
01048 {
01049
01050 ms_threadWaitNr++;
01051 myWaitNr = ms_threadWaitNr;
01052 #ifdef DEBUG
01053 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Thread %x waits for connection with waitNr %Lu and %Lu Threads waiting before\n",
01054 pthread_self(), myWaitNr, (myWaitNr - ms_nextThreadNr));
01055 #endif
01056 while(ms_nextThreadNr != myWaitNr)
01057 {
01058 ms_pConnectionAvailable->wait();
01059 }
01060 #ifdef DEBUG
01061 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Thread %x with waitNr %Lu continues\n",
01062 pthread_self(), myWaitNr);
01063 #endif
01064 if(ms_threadWaitNr == ms_nextThreadNr)
01065 {
01066
01067 ms_threadWaitNr = 0;
01068 ms_nextThreadNr = 0;
01069 }
01070
01071 }
01072 }
01073 ms_pConnectionAvailable->unlock();
01074 if(returnedConnection != NULL)
01075 {
01076 if(!(returnedConnection->checkConnectionStatus()))
01077 {
01078 if(returnedConnection->initDBConnection() != E_SUCCESS)
01079 {
01080 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
01081 CAMsg::printMsg(LOG_WARNING, "CAAccountingDBInterface: Warning requested DB connection can not be established\n");
01082
01083
01084 }
01085 else
01086 {
01087 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
01088 }
01089 }
01090 else
01091 {
01092 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
01093 }
01094 }
01095 return returnedConnection;
01096 }
01097
01098
01099
01100
01101
01102
01103
01104 SINT32 CAAccountingDBInterface::releaseConnection(CAAccountingDBInterface *dbIf)
01105 {
01106 SINT32 ret;
01107
01108 if(dbIf == NULL)
01109 {
01110 return E_UNKNOWN;
01111 }
01112 if(dbIf->m_pConnectionMutex == NULL)
01113 {
01114 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnection structure corrupt!\n");
01115 return E_UNKNOWN;
01116 }
01117 if(ms_pConnectionAvailable == NULL)
01118 {
01119 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnections not initialized. This should NEVER happen!\n");
01120 return E_UNKNOWN;
01121 }
01122
01123 ms_pConnectionAvailable->lock();
01124 if(dbIf->testAndResetOwner())
01125 {
01126 if(ms_threadWaitNr != ms_nextThreadNr)
01127 {
01128 ms_nextThreadNr++;
01129 #ifdef DEBUG
01130 CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: There are %Lu Threads waiting. Waking up thread with waitNr. %Lu\n",
01131 (ms_threadWaitNr - ms_nextThreadNr), ms_nextThreadNr);
01132 #endif
01133
01134 ms_pConnectionAvailable->broadcast();
01135 }
01136 ret = E_SUCCESS;
01137 }
01138 else
01139 {
01140 ret = E_UNKNOWN;
01141 }
01142 ms_pConnectionAvailable->unlock();
01143 return ret;
01144 }
01145
01146 bool CAAccountingDBInterface::testAndSetOwner()
01147 {
01148 bool success = false;
01149 m_pConnectionMutex->lock();
01150 if(m_free)
01151 {
01152 m_free = false;
01153 m_owner = CAThread::getSelfID();
01154 success = true;
01155 }
01156 m_pConnectionMutex->unlock();
01157 return success;
01158 }
01159
01160 bool CAAccountingDBInterface::testAndResetOwner()
01161 {
01162 bool success = false;
01163 m_pConnectionMutex->lock();
01164 if(!m_free && (m_owner == CAThread::getSelfID()))
01165 {
01166 m_free = true;
01167 m_owner = 0;
01168 success = true;
01169 }
01170 m_pConnectionMutex->unlock();
01171 return success;
01172 }
01173
01174 SINT32 CAAccountingDBInterface::init()
01175 {
01176 UINT32 i;
01177 SINT32 dbConnStatus;
01178
01179 ms_pConnectionAvailable = new CAConditionVariable();
01180
01181 ms_threadWaitNr = 0;
01182 ms_nextThreadNr = 0;
01183
01184 if(ms_pDBConnectionPool != NULL)
01185 {
01186 for(i=0; i < MAX_DB_CONNECTIONS; i++)
01187 {
01188 if(ms_pDBConnectionPool[i] != NULL)
01189 {
01190
01191
01192 }
01193 ms_pDBConnectionPool[i] = new CAAccountingDBInterface();
01194 dbConnStatus = ms_pDBConnectionPool[i]->initDBConnection();
01195
01196 if(dbConnStatus != E_SUCCESS)
01197 {
01198 CAMsg::printMsg(LOG_CRIT, "CAAccountingDBInterface: DBConnection initialization: "
01199 "could not connect to Database.\n");
01200 return E_UNKNOWN;
01201 }
01202 }
01203 }
01204 else
01205 {
01206 CAMsg::printMsg(LOG_CRIT, "CAAccountingDBInterface: DBConnection initialization failed.\n");
01207 return E_UNKNOWN;
01208 }
01209 return E_SUCCESS;
01210 }
01211
01212 SINT32 CAAccountingDBInterface::cleanup()
01213 {
01214 UINT32 i;
01215 SINT32 dbConnStatus, ret = E_SUCCESS;
01216 if(ms_pDBConnectionPool != NULL)
01217 {
01218 for(i=0; i < MAX_DB_CONNECTIONS; i++)
01219 {
01220 if(ms_pDBConnectionPool[i] == NULL)
01221 {
01222
01223 }
01224 else
01225 {
01226 dbConnStatus = ms_pDBConnectionPool[i]->terminateDBConnection();
01227 delete ms_pDBConnectionPool[i];
01228 ms_pDBConnectionPool[i] = NULL;
01229 }
01230 if(dbConnStatus != E_SUCCESS)
01231 {
01232 CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnection cleanup: "
01233 "an error occured while closing DBConnection.\n");
01234 ret = dbConnStatus;
01235 }
01236 }
01237 }
01238 if(ms_pConnectionAvailable != NULL)
01239 {
01240 delete ms_pConnectionAvailable;
01241 ms_pConnectionAvailable = NULL;
01242 }
01243 return ret;
01244 }
01245
01246 PGresult *CAAccountingDBInterface::monitored_PQexec(PGconn *conn, const char *query)
01247 {
01248 PGresult* result = NULL;
01249 result = PQexec(conn, query);
01250 if(!checkConnectionStatus())
01251 {
01252 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
01253 }
01254 else
01255 {
01256 MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
01257 }
01258 return result;
01259 }
01260
01261 #endif
01262
01263