Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

CAAccountingInstance.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team All rights reserved.
00003 Redistribution and use in source and binary forms, with or without
00004 modification, are permitted provided that the following conditions are
00005 met:
00006  
00007 - Redistributions of source code must retain the above copyright
00008 notice, this list of conditions and the following disclaimer.
00009  
00010 - Redistributions in binary form must reproduce the above
00011 copyright notice, this list of conditions and the following
00012 disclaimer in the documentation and/or other materials provided
00013 with the distribution.
00014  
00015 - Neither the name of the University of Technology Dresden,
00016 Germany nor the names of its contributors may be used to endorse
00017 or promote products derived from this software without specific
00018 prior written permission.
00019  
00020  
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00024 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
00025 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00027 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 
00032 */
00033 #include "StdAfx.h"
00034 #ifdef PAYMENT
00035 
00036 
00037 #include "CAAccountingInstance.hpp"
00038 #include "CAAccountingControlChannel.hpp"
00039 #include "CABase64.hpp"
00040 #include "CAMsg.hpp"
00041 #include "CAUtil.hpp"
00042 #include "CASignature.hpp"
00043 #include "CAXMLErrorMessage.hpp"
00044 
00045 
00046 
00047 /**
00048  * Singleton: This is the reference to the only instance of this class
00049  */
00050 CAAccountingInstance * CAAccountingInstance::ms_pInstance = NULL;
00051 
00052 
00053 
00054 /**
00055  * private Constructor
00056  */
00057 CAAccountingInstance::CAAccountingInstance()
00058   {
00059   
00060     CAMsg::printMsg( LOG_DEBUG, "AccountingInstance initialising\n" );
00061     m_pQueue = new CAQueue();
00062     m_pIPBlockList = new CATempIPBlockList(60000);
00063     
00064     // initialize Database connection
00065     m_dbInterface = new CAAccountingDBInterface();
00066     if(m_dbInterface->initDBConnection() != E_SUCCESS)
00067     {
00068       CAMsg::printMsg( LOG_ERR, "**************** AccountingInstance: Could not connect to DB!");
00069       exit(1);
00070     }
00071   
00072     // initialize JPI signataure tester
00073     m_AiName = new UINT8[256];
00074     options.getAiID(m_AiName, 256);
00075     m_pJpiVerifyingInstance = options.getBI()->getVerifier();
00076     options.getPaymentHardLimit(&m_iHardLimitBytes);
00077     options.getPaymentSoftLimit(&m_iSoftLimitBytes);
00078   
00079     // launch AI thread
00080     m_pThread = new CAThread();
00081     m_pThread->setMainLoop( aiThreadMainLoop );
00082     m_bThreadRunning = true;
00083     m_pThread->start( this );
00084     
00085     // launch BI settleThread
00086     m_pSettleThread = new CAAccountingSettleThread();
00087   }
00088 
00089 
00090 
00091 /**
00092  * private desctructor
00093  */
00094 CAAccountingInstance::~CAAccountingInstance()
00095   {
00096     CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying\n" );
00097     m_bThreadRunning = false;
00098     m_pThread->join();
00099     delete m_pThread;
00100     //delete m_biInterface;
00101     delete m_dbInterface;
00102     delete m_pIPBlockList;
00103     delete m_pQueue;
00104   }
00105 
00106 
00107 
00108 /**
00109  * This function is called by the FirstMix for each incoming JAP packet.
00110  * It counts the payload of normal packets and tells the mix when a connection 
00111  * should be closed because the user is not willing to pay.
00112  * 
00113  * @return 0 if the packet is an JAP->AI packet (caller should drop it)
00114  * @return 1 everything is OK, packet should be forwarded to next mix
00115  * @return 2 user did not send accountcertificate, connection should be closed
00116  * @return 3 user  did not send a cost confirmation 
00117  * or somehow tried to fake authentication, connection should be closed
00118  * @return 4 AuthState unknown (internal error, should not happen)
00119  */
00120 SINT32 CAAccountingInstance::handleJapPacket( MIXPACKET *pPacket, fmHashTableEntry *pHashEntry)
00121 {
00122   aiAccountingInfo * pAccInfo;
00123   timespec now; 
00124   getcurrentTime(now);
00125   pAccInfo = pHashEntry->pAccountingInfo;
00126   
00127   
00128   m_Mutex.lock();
00129   pAccInfo->transferredBytes += sizeof(MIXPACKET); // count the packet  
00130   
00131   if(pAccInfo->authFlags & (AUTH_FATAL_ERROR))
00132   {
00133     // there was an error earlier..
00134     return 3;
00135   }
00136   
00137   if(pAccInfo->authFlags & (AUTH_GOT_ACCOUNTCERT) )
00138   {
00139   
00140     //----------------------------------------------------------
00141     // authentication process not properly finished
00142     if( pAccInfo->authFlags & AUTH_FAKE )
00143       {
00144         m_Mutex.unlock();
00145         CAMsg::printMsg( LOG_DEBUG, "AccountingInstance: AUTH_FAKE flag is set ... byebye\n");
00146         return 3;
00147       }
00148     if( !(pAccInfo->authFlags & AUTH_ACCOUNT_OK) )
00149     {
00150       // we did not yet receive the response to the challenge...
00151       if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00152       {
00153         m_Mutex.unlock();
00154         CAMsg::printMsg( LOG_DEBUG, "AccountingInstance: Jap refused to send response to challenge (Request Timeout)...\n");
00155         return 3;
00156       }
00157     }
00158     
00159     if( pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )
00160       {
00161         CAMsg::printMsg( LOG_DEBUG, "AccountingInstance: Account is empty. Closing connection.\n");
00162         CAXMLErrorMessage msg(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
00163         DOM_Document doc;
00164         msg.toXmlDocument(doc);
00165         pAccInfo->pControlChannel->sendMessage(doc);
00166         pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00167         m_Mutex.unlock();
00168         return 3;
00169       }
00170 
00171     //----------------------------------------------------------
00172     // Hardlimit corstconfirmation check
00173     else if ((pAccInfo->transferredBytes-pAccInfo->confirmedBytes) >= m_iHardLimitBytes)
00174       {
00175         #ifdef DEBUG
00176         CAMsg::printMsg( LOG_DEBUG, "Accounting instance: User refused "
00177                           "to send cost confirmation (HARDLIMIT EXCEEDED).\n");
00178         #endif
00179         m_pIPBlockList->insertIP( pHashEntry->peerIP );
00180         CAXMLErrorMessage msg(CAXMLErrorMessage::ERR_NO_CONFIRMATION);
00181         DOM_Document doc;
00182         msg.toXmlDocument(doc);
00183         pAccInfo->pControlChannel->sendMessage(doc);
00184         pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00185         m_Mutex.unlock();
00186         return 3;
00187       }
00188   
00189     //-------------------------------------------------------
00190     // check: is it time to request a new cost confirmation?
00191     else if( (pAccInfo->transferredBytes-pAccInfo->confirmedBytes) >= m_iSoftLimitBytes)
00192     {
00193       if( (pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
00194       {
00195         if( (pAccInfo->authFlags & AUTH_SENT_SECOND_CC_REQUEST))
00196         {
00197           if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00198           {
00199             #ifdef DEBUG
00200             CAMsg::printMsg( LOG_DEBUG, "Accounting instance: User refused "
00201                               "to send cost confirmation (REQUEST TIMEOUT).\n");
00202             #endif
00203             m_pIPBlockList->insertIP( pHashEntry->peerIP );
00204             CAXMLErrorMessage msg(CAXMLErrorMessage::ERR_NO_CONFIRMATION);
00205             DOM_Document doc;
00206             msg.toXmlDocument(doc);
00207             pAccInfo->pControlChannel->sendMessage(doc);
00208             pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00209             m_Mutex.unlock();
00210             return 3;
00211           }
00212           else
00213           {
00214             m_Mutex.unlock();
00215             return 1;
00216           }
00217         }
00218         else if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00219         {
00220           // send a reminder...
00221           DOM_Document doc;
00222           #ifdef DEBUG
00223           CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending REMINDER CC request.\n");
00224           #endif
00225           makeCCRequest(pAccInfo->accountNumber, pAccInfo->transferredBytes, doc);
00226           pAccInfo->pControlChannel->sendMessage(doc);
00227           pAccInfo->authFlags |= AUTH_SENT_SECOND_CC_REQUEST;
00228           pAccInfo->lastRequestSeconds = now.tv_sec;
00229           m_Mutex.unlock();
00230           return 1;
00231         }
00232         else
00233         {
00234           m_Mutex.unlock();
00235           return 1;
00236         }
00237       }
00238       else
00239       {
00240         // send a first CC request
00241         DOM_Document doc;
00242         #ifdef DEBUG
00243         CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending CC request.\n");
00244         #endif
00245         makeCCRequest(pAccInfo->accountNumber, pAccInfo->transferredBytes, doc);
00246         pAccInfo->pControlChannel->sendMessage(doc);
00247         pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
00248         pAccInfo->lastRequestSeconds = now.tv_sec;
00249         m_Mutex.unlock();
00250         return 1;
00251       }
00252     }
00253     else
00254     {
00255       //--------------------------------------------------------------
00256       // check: do we need a new balance certificate for the account?
00257       /// TODO: Make the numbers vvv configurable
00258       if( (( (pAccInfo->transferredBytes - pAccInfo->lastbalTransferredBytes) >=
00259           ((pAccInfo->lastbalDeposit - pAccInfo->lastbalSpent) / 33))&&
00260           ((pAccInfo->transferredBytes - pAccInfo->lastbalTransferredBytes) >= 256*1024))
00261           || (pAccInfo->lastbalDeposit == 0))
00262       {
00263         if( (pAccInfo->authFlags & AUTH_SENT_BALANCE_REQUEST) )
00264         {
00265           if( (pAccInfo->authFlags & AUTH_SENT_SECOND_BALANCE_REQUEST))
00266           {
00267             if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00268             {
00269               #ifdef DEBUG
00270               CAMsg::printMsg( LOG_DEBUG, "Accounting instance: User refused "
00271                                 "to send balance cert (request Timeout).\n",
00272                                 pAccInfo->accountNumber, pHashEntry->peerIP[ 0 ], pHashEntry->peerIP[ 1 ],
00273                                 pHashEntry->peerIP[ 2 ], pHashEntry->peerIP[ 3 ] );
00274               #endif
00275               m_pIPBlockList->insertIP( pHashEntry->peerIP );
00276               CAXMLErrorMessage msg(CAXMLErrorMessage::ERR_NO_BALANCE);
00277               DOM_Document doc;
00278               msg.toXmlDocument(doc);
00279               pAccInfo->pControlChannel->sendMessage(doc);
00280               pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00281               m_Mutex.unlock();
00282               return 3;
00283             }
00284             else
00285             {
00286               m_Mutex.unlock();
00287               return 1;
00288             }
00289           }
00290           else if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00291           {
00292             // send a reminder...
00293             // TODO adjust "newerThan" value
00294             DOM_Document doc;
00295             #ifdef DEBUG
00296             CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending REMINDER balance request.\n");
00297             #endif
00298             makeBalanceRequest((SINT32)now.tv_sec-600, doc);
00299             pAccInfo->reqbalMinSeconds = now.tv_sec - 600;
00300             pAccInfo->pControlChannel->sendMessage(doc);
00301             pAccInfo->authFlags |= AUTH_SENT_SECOND_BALANCE_REQUEST;
00302             pAccInfo->lastRequestSeconds = now.tv_sec;
00303             m_Mutex.unlock();
00304             return 1;
00305           }
00306           else
00307           {
00308             m_Mutex.unlock();
00309             return 1;
00310           }
00311         }
00312         else
00313         {
00314           // send a first CC request
00315           DOM_Document doc;
00316           makeBalanceRequest(now.tv_sec-600, doc);
00317           #ifdef DEBUG
00318           CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending balance request.\n");
00319           #endif
00320           pAccInfo->reqbalMinSeconds = now.tv_sec - 600;
00321           pAccInfo->pControlChannel->sendMessage(doc);
00322           pAccInfo->authFlags |= AUTH_SENT_BALANCE_REQUEST;
00323           pAccInfo->lastRequestSeconds = now.tv_sec;
00324           m_Mutex.unlock();
00325           return 1;
00326         }
00327       }
00328       else
00329       {
00330         // let the packet pass thru
00331         m_Mutex.unlock();
00332         return 1;
00333       }
00334     }
00335   }
00336   else
00337   {
00338     //---------------------------------------------------------
00339     // we have no accountcert from the user, let's request one
00340     
00341     if(pAccInfo->authFlags & AUTH_SENT_ACCOUNT_REQUEST)
00342     {
00343       if(pAccInfo->authFlags & AUTH_SENT_SECOND_ACCOUNT_REQUEST)
00344       {
00345         // just wait for answer
00346         if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00347         {
00348           // timeout
00349           #ifdef DEBUG
00350           CAMsg::printMsg( LOG_DEBUG, "Accounting instance: User refused "
00351                         "to send account certificate.(request timeout)\n");
00352           #endif
00353           CAXMLErrorMessage msg(CAXMLErrorMessage::ERR_NO_ACCOUNTCERT);
00354           DOM_Document doc;
00355           msg.toXmlDocument(doc);
00356           pAccInfo->pControlChannel->sendMessage(doc);
00357           pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00358           m_Mutex.unlock();
00359           return 2;
00360         }
00361         m_Mutex.unlock();
00362         return 1;
00363       }
00364       if(now.tv_sec >= pAccInfo->lastRequestSeconds + REQUEST_TIMEOUT)
00365       {
00366         // send reminder
00367         #ifdef DEBUG
00368         CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending REMINDER account request.\n");
00369         #endif
00370         DOM_Document doc;
00371         makeAccountRequest(doc);
00372         pAccInfo->pControlChannel->sendMessage(doc);
00373         pAccInfo->authFlags |= AUTH_SENT_SECOND_ACCOUNT_REQUEST;
00374         pAccInfo->lastRequestSeconds = now.tv_sec;
00375       }
00376       m_Mutex.unlock();
00377       return 1;
00378     }
00379     else
00380     {
00381       // send first request
00382       #ifdef DEBUG
00383       CAMsg::printMsg(LOG_DEBUG, "AccountingInstance sending account request.\n");
00384       #endif
00385       DOM_Document doc;
00386       makeAccountRequest(doc);
00387       pAccInfo->pControlChannel->sendMessage(doc);
00388       pAccInfo->authFlags |= AUTH_SENT_ACCOUNT_REQUEST;
00389       pAccInfo->lastRequestSeconds = now.tv_sec;
00390       m_Mutex.unlock();
00391       return 1;
00392     }
00393   }
00394   CAMsg::printMsg(LOG_ERR, 
00395       "Unknown error in CAAccountingInstance::handleJapPacket()."
00396       "..... this should never happen!\n"
00397     );
00398   return 4;
00399 }
00400 
00401 
00402 /** TODO: maybe make this an own CAAbstractXMLEncodable subclass */
00403 SINT32 CAAccountingInstance::makeCCRequest(const UINT64 accountNumber, const UINT64 transferredBytes, DOM_Document& doc)
00404 {
00405   // create a DOM CostConfirmation document
00406   doc = DOM_Document::createDocument();
00407   DOM_Element elemRoot = doc.createElement("PayRequest");
00408   elemRoot.setAttribute("version", "1.0");
00409   doc.appendChild(elemRoot);
00410   
00411   DOM_Element elemCC = doc.createElement("CC");
00412   elemCC.setAttribute("version", "1.0");
00413   elemRoot.appendChild(elemCC);
00414   
00415   DOM_Element elemAiName = doc.createElement("AiID");
00416   setDOMElementValue(elemAiName, m_AiName);
00417   elemCC.appendChild(elemAiName);
00418   
00419   DOM_Element elemAccount = doc.createElement("AccountNumber");
00420   setDOMElementValue(elemAccount, (UINT64)accountNumber);
00421   elemCC.appendChild(elemAccount);
00422 
00423   DOM_Element elemBytes = doc.createElement("TransferredBytes");
00424   setDOMElementValue(elemBytes, transferredBytes);
00425   elemCC.appendChild(elemBytes);
00426   
00427   return E_SUCCESS;
00428 }
00429 
00430 /** TODO: maybe make this an own CAAbstractXMLEncodable subclass */
00431 SINT32 CAAccountingInstance::makeBalanceRequest(const SINT32 seconds, DOM_Document &doc)
00432 {
00433   UINT8 timeBuf[128];
00434   UINT32 timeBufLen = 128;
00435   
00436   doc = DOM_Document::createDocument();
00437   DOM_Element elemRoot = doc.createElement("PayRequest");
00438   elemRoot.setAttribute("version", "1.0");
00439   doc.appendChild(elemRoot);
00440   DOM_Element elemAcc = doc.createElement("BalanceRequest");
00441   elemRoot.appendChild(elemAcc);
00442   DOM_Element elemDate = doc.createElement("NewerThan");
00443   elemAcc.appendChild(elemDate);
00444   formatJdbcTimestamp(seconds, timeBuf, timeBufLen);
00445   setDOMElementValue(elemDate, timeBuf);
00446   return E_SUCCESS;
00447 }
00448 
00449 /** TODO: maybe make this an own CAAbstractXMLEncodable subclass */
00450 SINT32 CAAccountingInstance::makeAccountRequest(DOM_Document &doc)
00451 {
00452   doc = DOM_Document::createDocument();
00453   DOM_Element elemRoot = doc.createElement("PayRequest");
00454   elemRoot.setAttribute("version", "1.0");
00455   doc.appendChild(elemRoot);
00456   DOM_Element elemAcc = doc.createElement("AccountRequest");
00457   elemRoot.appendChild(elemAcc);
00458   return E_SUCCESS;
00459 }
00460 
00461 
00462 
00463 /**
00464  * The Main Loop of the accounting instance thread.
00465  * Reads messages out of the queue and processes them
00466  */
00467 THREAD_RETURN CAAccountingInstance::aiThreadMainLoop( void *param )
00468 {
00469   CAAccountingInstance * instance;
00470   aiQueueItem item;
00471   UINT32 itemSize;
00472   instance = ( CAAccountingInstance * ) param;
00473   CAMsg::printMsg( LOG_DEBUG, "AI Thread starting\n" );
00474 
00475   while ( instance->m_bThreadRunning )
00476     {
00477       itemSize = sizeof( aiQueueItem );
00478       instance->m_pQueue->getOrWait( (UINT8*)&item, &itemSize );
00479       instance->processJapMessage( item.pHashEntry, item.pDomDoc );
00480       //delete item.domDoc; (??)
00481     }
00482     
00483   return (THREAD_RETURN)0;
00484 }
00485 
00486 
00487 
00488 /**
00489  * Handle a user (xml) message sent to us by the Jap. 
00490  *  
00491  * This function is running inside the AiThread. It determines 
00492  * what type of message we have and calls the appropriate handle...() 
00493  * function
00494  */
00495 void CAAccountingInstance::processJapMessage(fmHashTableEntry * pHashEntry,DOM_Document * pDomDoc)
00496 {
00497   DOM_Element root = pDomDoc->getDocumentElement();
00498   char * docElementName = root.getTagName().transcode();
00499 
00500   // what type of message is it?
00501   if ( strcmp( docElementName, "AccountCertificate" ) == 0 )
00502     {
00503       #ifdef DEBUG
00504         CAMsg::printMsg( LOG_DEBUG, "Received an AccountCertificate. Calling handleAccountCertificate()\n" );
00505       #endif
00506       handleAccountCertificate( pHashEntry, root );
00507     }
00508   else if ( strcmp( docElementName, "Response" ) == 0)
00509     {
00510       #ifdef DEBUG
00511         CAMsg::printMsg( LOG_DEBUG, "Received a Response (challenge-response)\n");
00512       #endif
00513       handleChallengeResponse( pHashEntry, root );
00514     }
00515   else if ( strcmp( docElementName, "CC" ) == 0 )
00516     {
00517       #ifdef DEBUG
00518         CAMsg::printMsg( LOG_DEBUG, "Received a CC. Calling handleCostConfirmation()\n" );
00519       #endif
00520       handleCostConfirmation( pHashEntry, root );
00521     }
00522   else if ( strcmp( docElementName, "Balance" ) == 0 )
00523     {
00524       #ifdef DEBUG
00525         CAMsg::printMsg( LOG_DEBUG, "Received a BalanceCertificate. Calling handleBalanceCertificate()\n" );
00526       #endif
00527       handleBalanceCertificate( pHashEntry, root );
00528     }
00529   else
00530     {
00531       CAMsg::printMsg( 
00532           LOG_ERR, 
00533           "AI Received XML message with unknown root element \"%s\". Ignoring...\n",
00534           docElementName 
00535         );
00536     }
00537   delete pDomDoc;
00538   delete [] docElementName;
00539 }
00540 
00541 
00542 /**
00543  * Handles an account certificate of a newly connected Jap.
00544  * Parses accountnumber and publickey, checks the signature
00545  * and generates and sends a challenge XML structure to the 
00546  * Jap.
00547  * TODO: think about switching account without changing mixcascade
00548  *   (receive a new acc.cert. though we already have one)
00549  */
00550 void CAAccountingInstance::handleAccountCertificate(fmHashTableEntry *pHashEntry, DOM_Element &root)
00551 {
00552   aiAccountingInfo * pAccInfo = pHashEntry->pAccountingInfo;
00553   DOM_Element elGeneral;
00554   timespec now;
00555   getcurrentTime(now);
00556 
00557   // check authstate of this user
00558   m_Mutex.lock();
00559   if(pAccInfo->authFlags&AUTH_GOT_ACCOUNTCERT)
00560     {
00561       #ifdef DEBUG
00562         CAMsg::printMsg(LOG_DEBUG, "Already got an account cert. Ignoring!");
00563       #endif
00564       CAXMLErrorMessage err(
00565           CAXMLErrorMessage::ERR_BAD_REQUEST, 
00566           (UINT8*)"You have already sent an Account Certificate"
00567         );
00568       DOM_Document errDoc;
00569       err.toXmlDocument(errDoc);
00570       pAccInfo->pControlChannel->sendMessage(errDoc);
00571       m_Mutex.unlock();
00572       return ;
00573     }
00574 
00575   // parse & set accountnumber
00576   if ( getDOMChildByName( root, (UINT8 *)"AccountNumber", elGeneral, false ) != E_SUCCESS ||
00577       getDOMElementValue( elGeneral, pAccInfo->accountNumber ) != E_SUCCESS ||
00578       pAccInfo->accountNumber == 0 )
00579     {
00580       CAMsg::printMsg( LOG_ERR, "AccountCertificate has wrong or no accountnumber. Ignoring\n");
00581       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_FORMAT);
00582       DOM_Document errDoc;
00583       err.toXmlDocument(errDoc);
00584       pAccInfo->pControlChannel->sendMessage(errDoc);
00585       m_Mutex.unlock();
00586       return ;
00587     }
00588 
00589   // parse & set public key
00590   if ( getDOMChildByName( root, (UINT8 *)"JapPublicKey", elGeneral, false ) != E_SUCCESS )
00591     {
00592       CAMsg::printMsg( LOG_ERR, "AccountCertificate contains no public key. Ignoring\n");
00593       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
00594       DOM_Document errDoc;
00595       err.toXmlDocument(errDoc);
00596       pAccInfo->pControlChannel->sendMessage(errDoc);
00597       m_Mutex.unlock();
00598       return ;
00599     }
00600   #ifdef DEBUG
00601     UINT8* aij;
00602     UINT32 aijsize;
00603     aij = DOM_Output::dumpToMem(elGeneral, &aijsize);
00604     aij[aijsize-1]=0;
00605     CAMsg::printMsg( LOG_DEBUG, "Setting user public key %s>\n", aij );
00606     delete[] aij;
00607   #endif
00608   pAccInfo->pPublicKey = new CASignature();
00609   if ( pAccInfo->pPublicKey->setVerifyKey( elGeneral ) != E_SUCCESS )
00610     {
00611       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR);
00612       DOM_Document errDoc;
00613       err.toXmlDocument(errDoc);
00614       pAccInfo->pControlChannel->sendMessage(errDoc);
00615       m_Mutex.unlock();
00616       return ;
00617     }
00618 
00619   if ( (!m_pJpiVerifyingInstance)||
00620       (m_pJpiVerifyingInstance->verifyXML( (DOM_Node &)root, (CACertStore *)NULL ) != E_SUCCESS ))
00621     {
00622       // signature invalid. mark this user as bad guy
00623       CAMsg::printMsg( LOG_INFO, "CAAccountingInstance::handleAccountCertificate(): Bad Jpi signature\n" );
00624       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"Your account certificate is invalid");
00625       DOM_Document errDoc;
00626       err.toXmlDocument(errDoc);
00627       pAccInfo->pControlChannel->sendMessage(errDoc);
00628       pAccInfo->authFlags |= AUTH_FAKE | AUTH_GOT_ACCOUNTCERT;
00629       pAccInfo->authFlags &= ~AUTH_ACCOUNT_OK;
00630       m_Mutex.unlock();
00631       return ;
00632     }
00633     
00634   UINT8 * arbChallenge;
00635   UINT8 b64Challenge[ 512 ];
00636   UINT32 b64Len = 512;
00637 
00638   // generate random challenge data and Base64 encode it
00639   arbChallenge = ( UINT8* ) malloc( 222 );
00640   getRandom( arbChallenge, 222 );
00641   CABase64::encode( arbChallenge, 222, b64Challenge, &b64Len );
00642   if ( pAccInfo->pChallenge != NULL )
00643     delete[] pAccInfo->pChallenge;
00644   pAccInfo->pChallenge = arbChallenge; // store challenge for later..
00645 
00646   // generate XML challenge structure
00647   DOM_Document doc = DOM_Document::createDocument();
00648   DOM_Element elemRoot = doc.createElement( "Challenge" );
00649   DOM_Element elemPanic = doc.createElement( "DontPanic" );
00650   elemPanic.setAttribute( "version", "1.0" );
00651   doc.appendChild( elemRoot );
00652   elemRoot.appendChild( elemPanic );
00653   setDOMElementValue( elemPanic, b64Challenge );
00654 
00655   // send XML struct to Jap & set auth flags
00656   pAccInfo->pControlChannel->sendMessage(doc);
00657   pAccInfo->authFlags = AUTH_CHALLENGE_SENT | AUTH_GOT_ACCOUNTCERT;
00658   pAccInfo->lastRequestSeconds = now.tv_sec;
00659   m_Mutex.unlock();
00660 }
00661 
00662 
00663 
00664 
00665 /**
00666  * Handles the response to our challenge.
00667  * Checks the validity of the response and sets the user's authFlags
00668  * accordingly.
00669  */
00670 void CAAccountingInstance::handleChallengeResponse(fmHashTableEntry *pHashEntry, const DOM_Element &root)
00671 {
00672   UINT8 decodeBuffer[ 512 ];
00673   UINT32 decodeBufferLen = 512;
00674   UINT32 usedLen;
00675   DOM_Element elemPanic;
00676   //DSA_SIG * pDsaSig;
00677   aiAccountingInfo * pAccInfo = pHashEntry->pAccountingInfo;
00678 
00679   // check current authstate
00680   m_Mutex.lock();
00681   if( (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)) ||
00682       (!(pAccInfo->authFlags & AUTH_CHALLENGE_SENT))
00683     )
00684     {
00685       m_Mutex.unlock();
00686       return ;
00687     }
00688   pAccInfo->authFlags &= ~AUTH_CHALLENGE_SENT;
00689   //m_Mutex.unlock();
00690 
00691   // get raw bytes of response
00692   if ( getDOMElementValue( root, decodeBuffer, &decodeBufferLen ) != E_SUCCESS )
00693     {
00694       CAMsg::printMsg( LOG_DEBUG, "ChallengeResponse has wrong XML format. Ignoring\n" );
00695       return ;
00696     }
00697   usedLen = decodeBufferLen;
00698   decodeBufferLen = 512;
00699   CABase64::decode( decodeBuffer, usedLen, decodeBuffer, &decodeBufferLen );
00700 //  pDsaSig = DSA_SIG_new();
00701   
00702   //m_Mutex.lock();
00703   // check signature
00704   CASignature * sigTester = pHashEntry->pAccountingInfo->pPublicKey;
00705     #pragma message Signature verifying must be implemented here !!!!!!!!!!
00706   //sigTester->decodeRS( decodeBuffer, decodeBufferLen, pDsaSig );
00707   /// TODO: Really do signature checking here...
00708 /*  if ( sigTester->verifyDER( pHashEntry->pAccountingInfo->pChallenge, 222, decodeBuffer, decodeBufferLen ) 
00709     != E_SUCCESS )
00710     {
00711       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, 
00712           (UINT8*)"Challenge-response authentication failed!!\n");
00713       DOM_Document errDoc;
00714       err.toXmlDocument(errDoc);
00715       pAccInfo->pControlChannel->sendMessage(errDoc);
00716       pAccInfo->authFlags |= AUTH_FAKE;
00717       pAccInfo->authFlags &= ~AUTH_ACCOUNT_OK;
00718       m_Mutex.unlock();
00719       return ;
00720     }*/
00721     
00722   pAccInfo->authFlags |= AUTH_ACCOUNT_OK;
00723   
00724   // fetch cost confirmation from last session if available
00725   CAXMLCostConfirmation * pCC = NULL;
00726   m_dbInterface->getCostConfirmation(pAccInfo->accountNumber, &pCC);
00727   if(pCC!=NULL)
00728     {
00729       pAccInfo->transferredBytes += pCC->getTransferredBytes();
00730       #ifdef DEBUG
00731         CAMsg::printMsg(LOG_DEBUG, "TransferredBytes is now %lld\n", pAccInfo->transferredBytes);
00732       #endif
00733       pAccInfo->confirmedBytes = pCC->getTransferredBytes();
00734       delete pCC;
00735     }
00736   
00737   if ( pHashEntry->pAccountingInfo->pChallenge != NULL ) // free mem
00738     {
00739       delete[] pHashEntry->pAccountingInfo->pChallenge;
00740       pHashEntry->pAccountingInfo->pChallenge = NULL;
00741     }
00742   m_Mutex.unlock();
00743 }
00744 
00745 
00746 
00747 /**
00748  * Handles a cost confirmation sent by a jap
00749  */
00750 void CAAccountingInstance::handleCostConfirmation(fmHashTableEntry *pHashEntry,DOM_Element &root)
00751 {
00752   aiAccountingInfo *pAccInfo;
00753   
00754   pAccInfo = pHashEntry->pAccountingInfo;
00755   m_Mutex.lock();
00756   
00757   // check authstate  
00758   if( (!pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
00759       (!pAccInfo->authFlags & AUTH_ACCOUNT_OK))
00760     {
00761       m_Mutex.unlock();
00762       return ;
00763     }
00764     
00765     
00766   // for debugging only: test signature the oldschool way
00767   // warning this removes the signature from doc!!!
00768 /*  if ( (!pAccInfo->pPublicKey)||
00769       (pAccInfo->pPublicKey->verifyXML( (DOM_Node &)root ) != E_SUCCESS ))
00770     {
00771       // wrong signature
00772       CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
00773       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
00774       DOM_Document errDoc;
00775       err.toXmlDocument(errDoc);
00776       pAccInfo->pControlChannel->sendMessage(errDoc);
00777       m_Mutex.unlock();
00778       return ;
00779     }*/
00780     
00781 
00782   CAXMLCostConfirmation cc(root);
00783   
00784   // TODO: Make this work.... :-//
00785   if( cc.verifySignature( *(pAccInfo->pPublicKey)) != E_SUCCESS)
00786     {
00787       // wrong signature
00788       CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE! (IGNORING)\n" );
00789       /*CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
00790       DOM_Document errDoc;
00791       err.toXmlDocument(errDoc);
00792       pAccInfo->pControlChannel->sendMessage(errDoc);
00793       m_Mutex.unlock();
00794       return ;*/
00795     }
00796   #ifdef DEBUG
00797   else
00798     {
00799       CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
00800     }
00801   #endif
00802   m_Mutex.unlock();
00803   
00804 
00805   // parse and check AI name
00806   UINT8 * pAiID = cc.getAiID();
00807   if( strcmp( (char *)pAiID, (char *)m_AiName ) != 0)
00808     {
00809       CAMsg::printMsg( LOG_INFO, "CostConfirmation has wrong AIName %s. Ignoring...\n", pAiID );
00810       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA, (UINT8*)"Your CostConfirmation has a wrong AI name");
00811       DOM_Document errDoc;
00812       err.toXmlDocument(errDoc);
00813       pAccInfo->pControlChannel->sendMessage(errDoc);
00814       delete[] pAiID;
00815       return ;
00816     }
00817   delete[] pAiID;
00818 
00819   // parse & set transferredBytes
00820   m_Mutex.lock();
00821   if(cc.getTransferredBytes() < pAccInfo->confirmedBytes )
00822     {
00823       CAMsg::printMsg( LOG_INFO, "CostConfirmation has Wrong Number of Bytes (%lld). Ignoring...\n", cc.getTransferredBytes() );
00824       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA, 
00825         (UINT8*)"Your CostConfirmation has a wrong number of transferred bytes");
00826       DOM_Document errDoc;
00827       err.toXmlDocument(errDoc);
00828       pAccInfo->pControlChannel->sendMessage(errDoc);
00829       m_Mutex.unlock();
00830       return ;
00831     }
00832   pAccInfo->confirmedBytes = cc.getTransferredBytes();
00833   if(pAccInfo->confirmedBytes >= pAccInfo->reqConfirmBytes)
00834   {
00835     pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
00836     pAccInfo->authFlags &= ~AUTH_SENT_SECOND_CC_REQUEST;
00837   }
00838   m_Mutex.unlock();
00839   
00840   m_dbInterface->storeCostConfirmation( cc );
00841   return ;
00842 }
00843 
00844 
00845 
00846 /**
00847  * Handles a balance certificate sent by the JAP.
00848  * Checks signature and age.
00849  * @todo set authFlags
00850  * @todo send back XMLErrorMessages on failure
00851  */
00852 void CAAccountingInstance::handleBalanceCertificate(fmHashTableEntry *pHashEntry, const DOM_Element &root)
00853 {
00854   CASignature * pSigTester;
00855   UINT8 strGeneral[ 256 ];
00856   UINT32 strGeneralLen = 256;
00857   UINT64 newDeposit, newSpent;
00858   SINT32 seconds;
00859   DOM_Element elGeneral;
00860   aiAccountingInfo * pAccInfo = pHashEntry->pAccountingInfo;
00861   
00862 
00863   // test signature
00864   m_Mutex.lock();
00865   //pSigTester = pHashEntry->pAccountingInfo->pPublicKey;
00866   if( !m_pJpiVerifyingInstance || 
00867       (m_pJpiVerifyingInstance->verifyXML( (DOM_Node &)root, (CACertStore *)NULL ) != E_SUCCESS) 
00868     )
00869     {
00870       CAMsg::printMsg( LOG_INFO, "BalanceCertificate has BAD SIGNATURE! Ignoring\n" );
00871       m_Mutex.unlock();
00872       return ;
00873     }
00874   m_Mutex.unlock();
00875 
00876   // parse timestamp
00877   if ( (getDOMChildByName( root, (UINT8*)"Timestamp", elGeneral, false ) != E_SUCCESS) 
00878     || (getDOMElementValue( elGeneral, strGeneral, &strGeneralLen ) != E_SUCCESS) )
00879     {
00880       return ;
00881     }
00882   parseJdbcTimestamp(strGeneral, seconds);
00883   
00884   m_Mutex.lock();
00885   if(seconds < pAccInfo->reqbalMinSeconds)
00886   {
00887     // todo send a request again...
00888     // TODO: if too old -> ask JPI for a new one
00889     // if JPI is not available at present -> let user proceed for a while
00890     m_Mutex.unlock();
00891     return ;
00892   }
00893   //pAccInfo->lastbalSeconds = seconds;
00894   
00895   // parse & set deposit
00896   if( (getDOMChildByName( root, (UINT8*)"Deposit", elGeneral, false ) != E_SUCCESS) ||
00897       (getDOMElementValue( elGeneral, newDeposit ) != E_SUCCESS) ||
00898       (newDeposit < pAccInfo->lastbalDeposit) )
00899   {
00900     m_Mutex.unlock();
00901     #ifdef DEBUG
00902       CAMsg::printMsg(LOG_DEBUG, "invalid deposit value...");
00903     #endif
00904     return;
00905   }
00906   #ifdef DEBUG
00907   else {
00908     CAMsg::printMsg(LOG_DEBUG, "Balance: deposit=%lld\n", newDeposit);
00909   }
00910   #endif
00911   
00912   // parse & set spent
00913   if( (getDOMChildByName( root, (UINT8*)"Spent", elGeneral, false ) != E_SUCCESS) ||
00914       (getDOMElementValue( elGeneral, newSpent ) != E_SUCCESS) ||
00915       (newSpent < pAccInfo->lastbalSpent) )
00916   {
00917     m_Mutex.unlock();
00918     #ifdef DEBUG
00919       CAMsg::printMsg(LOG_DEBUG, "invalid spent value...");
00920     #endif
00921     return;
00922   }
00923   #ifdef DEBUG
00924   else {
00925     CAMsg::printMsg(LOG_DEBUG, "Balance: Spent=%lld\n", newSpent);
00926   }
00927   #endif
00928   
00929   // some checks for empty accounts
00930   if( (newDeposit-newSpent <= MIN_BALANCE ) ||
00931       ((newDeposit-newSpent-pAccInfo->transferredBytes) <= MIN_BALANCE ) 
00932     )
00933   {
00934     // mark account as empty
00935     pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
00936   }
00937   
00938   pAccInfo->lastbalDeposit = newDeposit;
00939   pAccInfo->lastbalSpent = newSpent;
00940   pAccInfo->lastbalTransferredBytes = pAccInfo->transferredBytes;
00941   
00942   // everything is OK, situation normal
00943   pAccInfo->authFlags &= ~(AUTH_SENT_BALANCE_REQUEST|AUTH_SENT_SECOND_BALANCE_REQUEST);
00944   m_Mutex.unlock();
00945 }
00946 
00947 
00948 /**
00949  * This must be called whenever a JAP is connecting to init our per-user
00950  * data structures
00951  */
00952 SINT32 CAAccountingInstance::initTableEntry( fmHashTableEntry * pHashEntry )
00953 {
00954   pHashEntry->pAccountingInfo = new aiAccountingInfo;
00955   memset( pHashEntry->pAccountingInfo, 0, sizeof( aiAccountingInfo ) );
00956   return E_SUCCESS;
00957 }
00958 
00959 
00960 
00961 /**
00962  * This should always be called when closing a JAP connection
00963  * to cleanup the payment data structures
00964  * @todo rewrite
00965  */
00966 SINT32 CAAccountingInstance::cleanupTableEntry( fmHashTableEntry *pHashEntry )
00967 {
00968   aiAccountingInfo * pAccInfo;
00969   if ( pHashEntry->pAccountingInfo != 0 )
00970     {
00971       pAccInfo = pHashEntry->pAccountingInfo;
00972       if ( pAccInfo->pPublicKey )
00973         {
00974           delete pAccInfo->pPublicKey;
00975         }
00976       if ( pAccInfo->pChallenge )
00977         {
00978           delete [] pAccInfo->pChallenge;
00979         }
00980       delete pHashEntry->pAccountingInfo;
00981     }
00982   return E_SUCCESS;
00983 }
00984 
00985 
00986 
00987 #endif /* ifdef PAYMENT */

Generated on Sun Aug 7 23:30:49 2005 for Mixe for Privacy and Anonymity in the Internet by  doxygen 1.4.2