Mixe for Privacy and Anonymity in the Internet
CAAccountingInstance.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2000, The JAP-Team All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are
5 met:
6 
7 - Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 
10 - Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14 
15 - Neither the name of the University of Technology Dresden,
16 Germany nor the names of its contributors may be used to endorse
17 or promote products derived from this software without specific
18 prior written permission.
19 
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
32 */
33 #include "StdAfx.h"
34 #ifdef PAYMENT
35 
36 #include "CAAccountingInstance.hpp"
38 #include "CABase64.hpp"
39 #include "CAMsg.hpp"
40 #include "CAUtil.hpp"
41 #include "CASignature.hpp"
42 #include "CAThreadPool.hpp"
43 #include "CAXMLErrorMessage.hpp"
44 #include "Hashtable.hpp"
45 #include "packetintro.h"
46 #include "CALibProxytest.hpp"
47 
48 //for testing purposes only
49 #define JAP_DIGEST_LENGTH 28
50 
51 XERCES_CPP_NAMESPACE::DOMDocument* CAAccountingInstance::m_preparedCCRequest;
52 
58 
60 
62 
67 
69 
71 
73 
78  {
79  CAMsg::printMsg( LOG_DEBUG, "AccountingInstance initialising\n" );
81  m_pMutex = new CAMutex();
82  //m_pIPBlockList = new CATempIPBlockList(60000);
84  //m_loginHashTableChangeInProgress = false; //for synchronizing settlementTransactions of loginThreads and SettlementThread.
85  m_nextSettleNr = 0; //The next thread's number to alter the login hash table
86  m_settleWaitNr = 0; //The wait number when it is equal to nextSettle number it's the thread's turn has to to
87  //alter the login hash table
88  // initialize Database connection
89  //m_dbInterface = new CAAccountingDBInterface();
91  m_mix = callingMix;
92  /*if(m_dbInterface->initDBConnection() != E_SUCCESS)
93  {
94  CAMsg::printMsg( LOG_ERR, "**************** AccountingInstance: Could not connect to DB!\n");
95  exit(1);
96  }*/
97 
98  // initialize JPI signature tester
99  m_AiName = new UINT8[256];
101  if (CALibProxytest::getOptions()->getBI() != NULL)
102  {
103  //m_pJpiVerifyingInstance = CALibProxytest::getOptions()->getBI()->getVerifier();
105  }
108 
109  prepareCCRequest(callingMix, m_AiName);
110 
112  new Hashtable((UINT32 (*)(void *))Hashtable::hashUINT64, (SINT32 (*)(void *,void *))Hashtable::compareUINT64, 2000);
113 
114  m_certHashCC =
115  new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
116  for (UINT32 i = 0; i < m_allHashesLen; i++)
117  {
118  m_certHashCC->put(m_allHashes[i], m_allHashes[i]);
119  }
120 
121  // launch BI settleThread
124 
126  }
127 
128 
133  {
134  INIT_STACK;
135  BEGIN_STACK("~CAAccountingInstance");
136 
137  /*
138  * avoid calling this desctructor concurrently!
139  */
140  m_pMutex->lock();
141 
142  CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying\n" );
143  if (m_pSettleThread)
144  {
145  CAMsg::printMsg( LOG_DEBUG, "deleting m_pSettleThread\n" );
146  //m_pSettleThread->settle();
147  delete m_pSettleThread;
148  m_pSettleThread = NULL;
149  }
150 
151  if (m_aiThreadPool)
152  {
153  CAMsg::printMsg( LOG_DEBUG, "deleting m_aiThreadPool\n" );
154  delete m_aiThreadPool;
155  m_aiThreadPool = NULL;
156  }
157 
158  /*if (m_dbInterface)
159  {
160  CAMsg::printMsg( LOG_DEBUG, "termintaing dbConnection\n" );
161  m_dbInterface->terminateDBConnection();
162  delete m_dbInterface;
163  }
164  m_dbInterface = NULL;*/
165 
166 
167  delete m_pPiInterface;
168  m_pPiInterface = NULL;
169 
170  delete m_pSettlementMutex;
171  m_pSettlementMutex = NULL;
172  //delete m_pIPBlockList;
173  //m_pIPBlockList = NULL;
174 
175 
176  delete[] m_AiName;
177  m_AiName = NULL;
178 
180  {
181  m_currentAccountsHashtable->getMutex()->lock();
182  CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Clearing accounts hashtable...\n");
183  m_currentAccountsHashtable->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
184  CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Deleting accounts hashtable...\n" );
185  m_currentAccountsHashtable->getMutex()->unlock();
188  }
190  CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Accounts hashtable deleted.\n" );
191 
192  delete[] m_currentCascade;
193  m_currentCascade = NULL;
194 
195  if(m_certHashCC != NULL)
196  {
197  for (UINT32 i = 0; i < m_allHashesLen; i++)
198  {
199  UINT8* certHash = (UINT8*)m_certHashCC->remove(m_allHashes[i]);
200  }
201  m_certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
202  delete m_certHashCC;
203  m_certHashCC = NULL;
204  }
205 
206  if (m_allHashes)
207  {
208  for (UINT32 i = 0; i < m_allHashesLen; i++)
209  {
210  delete m_allHashes[i];
211  m_allHashes[i] = NULL;
212  }
213  delete[] m_allHashes;
214  }
215  m_allHashes = NULL;
216 
217  m_pMutex->unlock();
218 
219  delete m_pMutex;
220  m_pMutex = NULL;
221  FINISH_STACK("~CAAccountingInstance");
222 
223  CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying finished.\n" );
224  }
225 
227 {
228  if (pHashEntry == NULL)
229  {
230  return 0;
231  }
232 
233  tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
234 
235  if (pAccInfo == NULL)
236  {
237  return 0;
238  }
239 
240  return pAccInfo->authFlags;
241 }
242 
244 {
245  UINT32 users = 0;
246 
247  if (ms_pInstance != NULL)
248  {
251  {
252  // getting the size is an atomic operation and does not need synchronization
253  users = ms_pInstance->m_currentAccountsHashtable->getSize();
254  }
255  else
256  {
257  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Trying to access Hashtable after it has been disposed!!.\n");
258  }
260  }
261 
262  return users;
263 }
264 
265 
267 {
268  INIT_STACK;
269  BEGIN_STACK("CAAccountingInstance::processThread");
270 
271  aiQueueItem* item = (aiQueueItem*)a_param;
272  bool bDelete = false;
273  DOMElement *elem = item->pDomDoc->getDocumentElement();
274 
275  // call the handle function
276  (ms_pInstance->*(item->handleFunc))(item->pAccInfo, elem);
277 
278  item->pAccInfo->mutex->lock();
279  item->pAccInfo->nrInQueue--;
280  if (item->pAccInfo->authFlags & AUTH_DELETE_ENTRY &&
281  item->pAccInfo->nrInQueue == 0)
282  {
283  /*
284  * There is no more entry of this connection in the queue,
285  * and the connection is closed. We have to delete the entry.
286  */
287  bDelete = true;
288  CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Deleting account entry from AI thread.\n");
289  }
290 
291  if (item->pAccInfo->nrInQueue < 0)
292  {
293  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI thread found negative handle queue!\n");
294  }
295  item->pAccInfo->mutex->unlock();
296 
297  if (bDelete)
298  {
299  delete item->pAccInfo->mutex;
300  item->pAccInfo->mutex = NULL;
301  delete item->pAccInfo;
302  item->pAccInfo = NULL;
303  }
304 
305  delete item->pDomDoc;
306  item->pDomDoc = NULL;
307  delete item;
308  item = NULL;
309 
310  FINISH_STACK("CAAccountingInstance::processThread");
311 
313 }
314 
315 SINT32 CAAccountingInstance::handleJapPacket(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
316 {
317  SINT32 ret = handleJapPacket_internal(pHashEntry, a_bControlMessage, a_bMessageToJAP);
318 
319  INIT_STACK;
320  FINISH_STACK("CAAccountingInstance::handleJapPacket");
321 
322  return ret;
323 }
324 
335 SINT32 CAAccountingInstance::handleJapPacket_internal(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
336  {
337  INIT_STACK;
338  BEGIN_STACK("CAAccountingInstance::handleJapPacket");
339 
340  CAAccountingDBInterface *dbInterface = NULL;
341 
342  if (pHashEntry == NULL || pHashEntry->pAccountingInfo == NULL)
343  {
345  }
346 
347  tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
348  AccountLoginHashEntry* loginEntry = NULL;
349  CAXMLErrorMessage* err = NULL;
350 
351  pAccInfo->mutex->lock();
352 
353  if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
354  {
355  pAccInfo->mutex->unlock();
357  }
358 
359  //Should never happen since control flow assert that this method cannot be invoked
360  //when a login is not finished.
361  if ( (pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED) && !a_bMessageToJAP )
362  {
363  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: User violates login protocol");
364  pAccInfo->mutex->unlock();
366  }
367 
368  //still preparing to close connection -> no data is forwarded upstream and only control messages are
369  //sent downstream if a user connection is in this state.
370  if ( pAccInfo->authFlags & AUTH_FATAL_ERROR )
371  {
372  pAccInfo->mutex->unlock();
374  }
375 
376  if (a_bControlMessage)
377  {
378  pAccInfo->mutex->unlock();
380  }
381  else
382  {
383  // count the packet and continue checkings
384  pAccInfo->transferredBytes += MIXPACKET_SIZE;
385  pAccInfo->sessionPackets++;
386 #ifdef SDTFA
387  IncrementShmPacketCount();
388 #endif
389  }
390 
391  if (pAccInfo->authFlags & AUTH_MULTIPLE_LOGIN)
392  {
393  return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
394  }
395 
396  // do the following tests after a lot of Mix packets only (gain speed...)
398  pAccInfo->sessionPackets % PACKETS_BEFORE_NEXT_CHECK != 0)
399  {
400  //CAMsg::printMsg( LOG_DEBUG, "Now we gain some speed after %d session packets..., auth-flags: %x\n", pAccInfo->sessionPackets, pAccInfo->authFlags);
401  pAccInfo->mutex->unlock();
403  }
404 
405 
406  SAVE_STACK("CAAccountingInstance::handleJapPacket", "before accounts hash");
407 
409  {
410  // accounting instance is dying...
411  return returnKickout(pAccInfo);
412  }
413 
414  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
415  //Suppose, this section checks the flags set after settlement */
416  loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
417  if (loginEntry)
418  {
419  pAccInfo->authFlags &= ~loginEntry->authRemoveFlags;
420  //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Remove flag: %d\n", loginEntry->authRemoveFlags);
421 
422 
423  /*if (loginEntry->ownerRef != pHashEntry)
424  {
425  // this is not the latest connection of this user; kick him out...
426  pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
427  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
428  return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
429  }
430  else */
431  if (loginEntry->authFlags & AUTH_OUTDATED_CC)
432  {
433  loginEntry->authFlags &= ~AUTH_OUTDATED_CC;
434 
435  UINT8 tmp[32];
436  print64(tmp,pAccInfo->accountNumber);
437  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Fixing bytes from outdated CC for account %s...\n", tmp);
438  // we had stored an outdated CC; insert confirmed bytes from current CC here and also update client
439  CAXMLCostConfirmation * pCC = NULL;
440  bool bSettled;
441 
442  dbInterface = CAAccountingDBInterface::getConnection();//new CAAccountingDBInterface();
443  if(dbInterface != NULL)
444  {
445  dbInterface->getCostConfirmation(pAccInfo->accountNumber,
447  &pCC,
448  bSettled);
450  dbInterface = NULL;
451  }
452  /*ms_pInstance->m_dbInterface->getCostConfirmation(pAccInfo->accountNumber,
453  ms_pInstance->m_currentCascade, &pCC, bSettled);*/
454 
455  if (pCC != NULL)
456  {
457  if (bSettled)
458  {
459  pAccInfo->transferredBytes += loginEntry->confirmedBytes - pAccInfo->confirmedBytes;
460  pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
461  loginEntry->confirmedBytes = 0;
462  pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
463  pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
464  }
465  else
466  {
467  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: While trying to fix bytes from outdated CC,"
468  "another CC was received! Waiting for settlement... \n");
469  }
470  delete pCC;
471  pCC = NULL;
472  }
473  else
474  {
475  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Bytes from outdated CC could not be fixed!\n");
476  }
477  }
478  else if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
479  {
480  if(!(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY))
481  {
482  // Do not reset the flag, so that the confirmedBytes are always reset.
483  //loginEntry->authFlags &= ~AUTH_ACCOUNT_EMPTY;
484  pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
485  /* confirmedBytes = 0 leads to immediate disconnection.
486  * If confirmedBytes > 0, any remaining prepaid bytes may be used.
487  */
488  pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
489  if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
490  {
491  // this account is really empty; prevent an overflow in the prepaid bytes calculation
492  pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
493  }
494 
495  //CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Account %llu is empty!\n", pAccInfo->accountNumber);
496  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty with %d prepaid bytes, (transferred bytes: %llu, confirmed bytes: %llu)!\n",
497  pAccInfo->accountNumber, getPrepaidBytes(pAccInfo), pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
498  }
499 
500  }
501  else if (loginEntry->authFlags & AUTH_INVALID_ACCOUNT)
502  {
503  loginEntry->authFlags &= ~AUTH_INVALID_ACCOUNT;
504  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Found invalid account %llu ! Kicking out user...\n", pAccInfo->accountNumber);
506  }
507  else if (loginEntry->authFlags & AUTH_BLOCKED)
508  {
509  loginEntry->authFlags &= ~AUTH_BLOCKED;
510  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with blocked account %llu !\n", pAccInfo->accountNumber);
512  }
513  else if (loginEntry->authFlags & AUTH_DATABASE)
514  {
515  loginEntry->authFlags &= ~AUTH_DATABASE;
516  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with account %llu due to database error...\n", pAccInfo->accountNumber);
518  }
519  else if (loginEntry->authFlags & AUTH_UNKNOWN)
520  {
521  loginEntry->authFlags &= ~AUTH_UNKNOWN;
522  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Unknown error, account %llu! Kicking out user...\n", pAccInfo->accountNumber);
524  }
525  }
526  else
527  {
528  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: handleJapPacket %s,%s did not find user login hash entry for account %llu, owner/accInfo: %p/%p!\n",
529  (a_bMessageToJAP ? "downstream" : "upstream"),
530  (a_bControlMessage ? "ctl" : "data"),
531  pAccInfo->accountNumber, pAccInfo->ownerRef, pHashEntry->pAccountingInfo);
532  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
533  return returnKickout(pAccInfo);
534  }
535 
536  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
537 
538  if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
539  {
540  // There should be no time limit. The connections is simply closed after all prepaid bytes are gone.
541  pAccInfo->lastHardLimitSeconds = time(NULL);
542 
543  //#ifdef DEBUG
544 
545  //#endif
546 
547  if (getPrepaidBytes(pAccInfo) <= 0)
548  {
549  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty! Kicking out user...\n",
550  pAccInfo->accountNumber);
552  }
553  else
554  {
562  pAccInfo->mutex->unlock();
564  }
565  }
566 
568  //pAccInfo->mutex->lock();
569 
570  SAVE_STACK("CAAccountingInstance::handleJapPacket", "before err");
571 
572  if (err)
573  {
574  return returnPrepareKickout(pAccInfo, err);
575  }
576 
577  //----------------------------------------------------------
578  // ****** Hardlimit cost confirmation check **********
579  //counting unconfirmed bytes is not necessary anymore, since we deduct from prepaid bytes
580  //UINT32 unconfirmedBytes=diff64(pAccInfo->transferredBytes,pAccInfo->confirmedBytes);
581 
582  //confirmed and transferred bytes are cumulative, so they use UINT64 to store potentially huge values
583  //prepaid Bytes as the difference will be much smaller, but might be negative, so we cast to signed int
584  SINT32 prepaidBytes = getPrepaidBytes(pAccInfo);
585 
586  if (prepaidBytes < 0 || prepaidBytes <= (SINT32) ms_pInstance->m_iHardLimitBytes)
587  {
589 
590  if ((pAccInfo->authFlags & AUTH_HARD_LIMIT_REACHED) == 0)
591  {
592  pAccInfo->lastHardLimitSeconds = time(NULL);
593  pAccInfo->authFlags |= AUTH_HARD_LIMIT_REACHED;
594  }
595 
596 #ifdef DEBUG
597  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Hard limit of %d bytes triggered in %d seconds \n",
599  (pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT - time(NULL)));
600 #endif
601 
602  if ( ( (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT) && (prepaidBytes <= 0) )
603  || (prepaidBytes < 0 && (UINT32)(prepaidBytes * (-1)) >= prepaidInterval) )
604  {
605 //#ifdef DEBUG
606  char* strReason;
607  if (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT)
608  {
609  strReason = "timeout";
610  }
611  else
612  {
613  strReason = "negative prepaid interval exceeded";
614  }
615  CAMsg::printMsg( LOG_INFO, "Accounting instance: User refused "
616  "to send cost confirmation (HARDLIMIT EXCEEDED, %s). "
617  "PrepaidBytes were: %d\n", strReason, prepaidBytes);
618 //#endif
619 
620  //ms_pInstance->m_pIPBlockList->insertIP( pHashEntry->peerIP );
621  pAccInfo->lastHardLimitSeconds = 0;
623  }
624  else
625  {
626  if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
627  {
628  sendCCRequest(pAccInfo);
629  }
630  }
631  }
632  else
633  {
634  pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
635  }
636 
637  //-------------------------------------------------------
638  // *** SOFT LIMIT CHECK *** is it time to request a new cost confirmation?
639  if ( prepaidBytes < 0 || prepaidBytes <= (SINT32) ms_pInstance->m_iSoftLimitBytes )
640  {
641 #ifdef DEBUG
642  CAMsg::printMsg(LOG_ERR, "soft limit of %d bytes triggered \n",ms_pInstance->m_iSoftLimitBytes);
643 #endif
644  if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
645  {//we have sent a first CC request
646  // no CC request sent yet --> send a first CC request
647  sendCCRequest(pAccInfo);
648  }
649  }// end of soft limit exceeded
650 
651  //everything is fine! let the packet pass thru
652  pAccInfo->mutex->unlock();
654  }
655 
656 /******************************************************************/
657 //methods to provide a unified point of exit for handleJapPacket
658 /******************************************************************/
659 
660 
662 {
663  if (pAccInfo == NULL)
664  {
665  return 0;
666  }
667 
668  //most unlikely that either transferred bytes or confirmed bytes
669  //are > 0x8000000000000000
670 
671  SINT64 prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
672  //difference must be a value that fits into a signed 32 bit integer.
673  if ((prepaidBytes > 0) && (prepaidBytes & 0x7FFFFFFF00000000LL))
674  {
675  CAMsg::printMsg(LOG_CRIT, "PrepaidBytes overflow: %lld\n", prepaidBytes);
676  CAMsg::printMsg(LOG_INFO, "TransferredBytes: %llu ConfirmedBytes: %llu\n", pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
677  }
678  return (SINT32) prepaidBytes;
679 
680  /*SINT32 prepaidBytes;
681 #ifdef DEBUG
682  CAMsg::printMsg(LOG_INFO, "Calculating TransferredBytes: %llu ConfirmedBytes: %llu\n",
683  pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
684 #endif
685  if (pAccInfo->confirmedBytes > pAccInfo->transferredBytes)
686  {
687  prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
688  if (prepaidBytes < 0)
689  {
690  // PrepaidBytes should be greater than 0 !!!
691  UINT8 tmp[32], tmp2[32];
692  print64(tmp,pAccInfo->transferredBytes);
693  print64(tmp2,pAccInfo->confirmedBytes);
694 
695  CAMsg::printMsg(LOG_CRIT, "PrepaidBytes are way to high! Maybe a hacker attack? Or CC did get lost?\n");
696  CAMsg::printMsg(LOG_INFO, "TransferredBytes: %s ConfirmedBytes: %s\n", tmp, tmp2);
697  UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
698  prepaidBytes = (SINT32)prepaidInterval;
699  pAccInfo->transferredBytes = pAccInfo->confirmedBytes - prepaidInterval;
700  }
701  }
702  else
703  {
704  prepaidBytes = pAccInfo->transferredBytes - pAccInfo->confirmedBytes;
705  prepaidBytes *= -1;
706  }
707 
708  return prepaidBytes;*/
709 }
710 
715 {
716  UINT8 tmp[32];
717  print64(tmp,pAccInfo->accountNumber);
718  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: should kick out user with account %s now...\n", tmp);
720  pAccInfo->mutex->unlock();
722 }
723 
725 {
726  pAccInfo->mutex->lock();
728  pAccInfo->mutex->unlock();
729 }
730 
731 /* prepaid bytes are calculated like that */
733 {
734  pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
735 }
736 
737 /*
738  * hold packet, no timeout started
739  * (Usage: send an error message before kicking out the user:
740  * sets AUTH_FATAL_ERROR )
741  * IMPORTANT: You need to hold a lock for pAccInfo->mutex when invoking this.
742  * Postcondition is that pAccInfo->mutex is unlocked.
743  */
745 {
746  pAccInfo->authFlags |= AUTH_FATAL_ERROR;
747 
748  if (a_error)
749  {
750  //CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Sending error message...\n");
751  XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
752  a_error->toXmlDocument(doc);
753  delete a_error;
754  a_error = NULL;
755  //pAccInfo->sessionPackets = 0; // allow some pakets to pass by to send the control message
756  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before prepare Kickout send...\n");
757  pAccInfo->pControlChannel->sendXMLMessage(doc);
758  if (doc != NULL)
759  {
760  doc->release();
761  doc = NULL;
762  }
763  }
764  else
765  {
766  CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Should send error message, but none is available!\n");
767  }
768 
769  pAccInfo->mutex->unlock();
771 }
772 
773 SINT32 CAAccountingInstance::sendInitialCCRequest(tAiAccountingInfo* pAccInfo, CAXMLCostConfirmation *pCC, SINT32 prepaidBytes)
774 {
775  XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
776 
777  SINT32 ret = makeInitialCCRequest(pCC, doc, prepaidBytes);
778  if( (ret != E_SUCCESS) || (doc == NULL))
779  {
780  CAMsg::printMsg(LOG_ERR, "cannot send initial CC request, ret: %d\n", ret);
781  return E_UNKNOWN;
782  }
783 #ifdef DEBUG
784  UINT32 debuglen = 3000;
785  UINT8 debugout[3000];
786  DOM_Output::dumpToMem(doc,debugout,&debuglen);
787  debugout[debuglen] = 0;
788  CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
789 #endif
790  ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
791  if (doc != NULL)
792  {
793  doc->release();
794  doc = NULL;
795  }
796  return ret;
797 }
798 
800 {
801  INIT_STACK;
802  BEGIN_STACK("CAAccountingInstance::sendCCRequest");
803 
804  XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
806 
807  pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
808 
809  if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
810  {
811  // do not send further CC requests for this account
812  return E_SUCCESS;
813  }
814 
815  // prepaid bytes are "confirmed bytes - transfered bytes"
816  //UINT64 bytesToConfirm = pAccInfo->confirmedBytes + (prepaidInterval) - (pAccInfo->confirmedBytes - pAccInfo->transferredBytes);
817  pAccInfo->bytesToConfirm = (prepaidInterval) + pAccInfo->transferredBytes;
818  makeCCRequest(pAccInfo->accountNumber, pAccInfo->bytesToConfirm, doc);
819  //pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
820 #ifdef DEBUG
821  CAMsg::printMsg(LOG_DEBUG, "CC request sent for %llu bytes, transferrred bytes: %llu bytes.\n",pAccInfo->bytesToConfirm, pAccInfo->transferredBytes);
822  CAMsg::printMsg(LOG_DEBUG, "prepaid Interval: %u \n",prepaidInterval);
823 
824  UINT32 debuglen = 3000;
825  UINT8 debugout[3000];
826  DOM_Output::dumpToMem(doc,debugout,&debuglen);
827  debugout[debuglen] = 0;
828  CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
829 #endif
830 
831  //FINISH_STACK("CAAccountingInstance::sendCCRequest");
832 
833  SINT32 ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
834  if (doc != NULL)
835  {
836  doc->release();
837  doc = NULL;
838  }
839  return ret;
840 }
841 
842 
843 bool CAAccountingInstance::cascadeMatchesCC(CAXMLCostConfirmation *pCC)
844 {
845 
846  UINT8* certHash;
847  if(m_allHashesLen != pCC->getNumberOfHashes() )
848  {
849  return false;
850  }
851 
852  for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
853  {
854  certHash = pCC->getPriceCertHash(i);
855  if ((certHash = (UINT8*)m_certHashCC->getValue(certHash)) != NULL)
856  {
857 #ifdef DEBUG
858  CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
859 #endif
860  }
861  else
862  {
863 #ifdef DEBUG
864  CAMsg::printMsg(LOG_DEBUG, "CC do not match current cascade.\n");
865 #endif
866  return false;
867  }
868  }
869 #ifdef DEBUG
870  CAMsg::printMsg(LOG_DEBUG, "CC matches current Cascade.\n");
871 #endif
872  return true;
873 }
874 
887 {
889 
890  DOMElement* elemRoot = createDOMElement(m_preparedCCRequest,"PayRequest");
891  setDOMElementAttribute(elemRoot,"version",(UINT8*) "1.0");
892  m_preparedCCRequest->appendChild(elemRoot);
893  DOMElement* elemCC = createDOMElement(m_preparedCCRequest,"CC");
894  setDOMElementAttribute(elemCC,"version",(UINT8*) "1.2");
895  elemRoot->appendChild(elemCC);
896  DOMElement* elemAiName = createDOMElement(m_preparedCCRequest,"AiID");
897  setDOMElementValue(elemAiName, a_AiName);
898  elemCC->appendChild(elemAiName);
899 
900  //extract price certificate elements from cascadeInfo
901  //get cascadeInfo from CAMix(which makeCCRequest needs to extract the price certs
902  XERCES_CPP_NAMESPACE::DOMDocument* cascadeInfoDoc=NULL;
903  callingMix->getMixCascadeInfo(cascadeInfoDoc);
904 
905  DOMElement* cascadeInfoElem = cascadeInfoDoc->getDocumentElement();
906  DOMNodeList* allMixes = getElementsByTagName(cascadeInfoElem,"Mix");
907  UINT32 nrOfMixes = allMixes->getLength();
908  DOMNode** mixNodes = new DOMNode*[nrOfMixes]; //so we can use separate loops for extracting, hashing and appending
909 
910  DOMNode* curMixNode=NULL;
911  for (UINT32 i = 0, j = 0, count = nrOfMixes; i < count; i++, j++){
912  //cant use getDOMChildByName from CAUtil here yet, since it will always return the first child
913  curMixNode = allMixes->item(i);
914  if (getDOMChildByName(curMixNode,"PriceCertificate",mixNodes[j],true) != E_SUCCESS)
915  {
916  j--;
917  nrOfMixes--;
918  }
919  }
920 
921  //hash'em, and get subjectkeyidentifiers
922  UINT8 digest[SHA_DIGEST_LENGTH];
923  m_allHashes=new UINT8*[nrOfMixes];
924  m_allHashesLen = nrOfMixes;
925  UINT8** allSkis=new UINT8*[nrOfMixes];
926  DOMNode* skiNode=NULL;
927  for (UINT32 i = 0; i < nrOfMixes; i++){
928  UINT8* out=new UINT8[5000];
929  UINT32 outlen=5000;
930 
931  DOM_Output::makeCanonical(mixNodes[i],out,&outlen);
932  out[outlen] = 0;
933 #ifdef DEBUG
934  CAMsg::printMsg(LOG_DEBUG, "price cert to be hashed: %s",out);
935 #endif
936  SHA1(out,outlen,digest);
937  delete[] out;
938  out = NULL;
939 
940  UINT32 len = 1024;
941  UINT8* tmpBuff = new UINT8[len+1];
942  memset(tmpBuff, 0, len+1);
943  if(CABase64::encode(digest,SHA_DIGEST_LENGTH,tmpBuff,&len)!=E_SUCCESS)
944  return E_UNKNOWN;
945  //tmpBuff[len]=0;
946 
947 
948  //line breaks might have been added, and would lead to database problems
949  strtrim(tmpBuff); //return value ohny significant for NULL or all-whitespace string, ignore
950 
951  m_allHashes[i] = tmpBuff;
952  CAMsg::printMsg(LOG_DEBUG,"Price certificate hash of Mix %u is: %s\n", i, m_allHashes[i]);
953  //do not delete tmpBuff here, since we're using allHashes below
954 
955  if (getDOMChildByName(mixNodes[i],"SubjectKeyIdentifier",skiNode,true) != E_SUCCESS)
956  {
957  CAMsg::printMsg(LOG_CRIT,"Could not get mix id from price cert");
958  }
959 
960  allSkis[i] = (UINT8*) XMLString::transcode(skiNode->getFirstChild()->getNodeValue());
961 
962  }
963  //concatenate the hashes, and store for future reference to identify the cascade
964  m_currentCascade = new UINT8[256];
965  memset(m_currentCascade, 0, (sizeof(UINT8)*256 ));
966  for (UINT32 j = 0; j < nrOfMixes; j++)
967  {
968  //check for hash value size (should always be OK)
969  if (strlen((const char*)m_currentCascade) > ( 256 - strlen((const char*)m_allHashes[j]) ) )
970  {
971  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance::prepareCCRequest: "
972  "Too many/too long hash values, ran out of allocated memory\n");
973  return E_UNKNOWN;
974  }
975  if (j == 0)
976  {
977  m_currentCascade = (UINT8*) strcpy( (char*) m_currentCascade,(const char*)m_allHashes[j]);
978  } else
979  {
980  m_currentCascade = (UINT8*) strcat((char*)m_currentCascade,(char*)m_allHashes[j]);
981  }
982  }
983 
984  //and append to CC
985  DOMElement* elemPriceCerts = createDOMElement(m_preparedCCRequest,"PriceCertificates");
986  DOMElement* elemCert=NULL;
987  for (UINT32 i = 0; i < nrOfMixes; i++)
988  {
989  elemCert = createDOMElement(m_preparedCCRequest,"PriceCertHash");
990  //CAMsg::printMsg(LOG_DEBUG,"hash to be inserted in cc: index %d, value %s\n",i,m_allHashes[i]);
991  setDOMElementValue(elemCert,m_allHashes[i]);
992  //delete[] allHashes[i];
993  setDOMElementAttribute(elemCert,"id",allSkis[i]);
994  setDOMElementAttribute(elemCert, "position", i);
995  if (i == 0)
996  {
997  setDOMElementAttribute(elemCert,"isAI",(UINT8*)"true");
998  }
999  elemPriceCerts->appendChild(elemCert);
1000  }
1001  elemCC->appendChild(elemPriceCerts);
1002 #ifdef DEBUG
1003  CAMsg::printMsg(LOG_DEBUG, "finished method makeCCRequest\n");
1004 #endif
1005 
1006  delete[] mixNodes;
1007  mixNodes = NULL;
1008  //delete[] allHashes;
1009  delete[] allSkis;
1010  allSkis = NULL;
1011  return E_SUCCESS;
1012 
1013 }
1014 
1020 SINT32 CAAccountingInstance::makeInitialCCRequest(CAXMLCostConfirmation *pCC, XERCES_CPP_NAMESPACE::DOMDocument* & doc, SINT32 prepaidBytes)
1021  {
1022  if( (pCC == NULL) || (pCC->getXMLDocument() == NULL) ||
1023  (pCC->getXMLDocument()->getDocumentElement() == NULL) )
1024  {
1025  CAMsg::printMsg(LOG_ERR, "Error creating initial CCrequest (pCC ref: %p)\n", pCC);
1026  return E_UNKNOWN;
1027  }
1028  DOMNode* elemCC=NULL;
1029 
1030  doc = createDOMDocument();
1031  DOMNode *ccRoot = doc->importNode(pCC->getXMLDocument()->getDocumentElement(),true);
1032  doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
1033  setDOMElementAttribute(doc->getDocumentElement(), "initialCC", true);
1034  DOMElement *elemPrepaidBytes = createDOMElement(doc, "PrepaidBytes");
1035  setDOMElementValue(elemPrepaidBytes, prepaidBytes);
1036  getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
1037  if(elemCC == NULL)
1038  {
1039  return E_UNKNOWN;
1040  }
1041  doc->getDocumentElement()->replaceChild(ccRoot, elemCC);
1042  doc->getDocumentElement()->appendChild(elemPrepaidBytes);
1043  return E_SUCCESS;
1044  }
1045 
1046 SINT32 CAAccountingInstance::makeCCRequest(const UINT64 accountNumber, const UINT64 transferredBytes, XERCES_CPP_NAMESPACE::DOMDocument* & doc)
1047  {
1048  INIT_STACK;
1049  BEGIN_STACK("CAAccountingInstance::makeCCRequest");
1050 
1051  DOMNode* elemCC=NULL;
1052 
1053  doc = createDOMDocument();
1054  doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
1055 
1056  getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
1057 
1058  DOMElement* elemAccount = createDOMElement(doc,"AccountNumber");
1059  setDOMElementValue(elemAccount, accountNumber);
1060  elemCC->appendChild(elemAccount);
1061  DOMElement* elemBytes = createDOMElement(doc,"TransferredBytes");
1062  setDOMElementValue(elemBytes, transferredBytes);
1063  elemCC->appendChild(elemBytes);
1064 
1065  FINISH_STACK("CAAccountingInstance::makeCCRequest");
1066 
1067  return E_SUCCESS;
1068  }
1069 
1070 
1072  const UINT32 code,
1073  UINT8 * message)
1074  {
1075  SINT32 sendSuccess = E_SUCCESS;
1076  XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
1077  DOMElement *elemRoot = createDOMElement(doc, "LoginConfirmation");
1078  setDOMElementAttribute(elemRoot, "code", code);
1079  setDOMElementValue(elemRoot, message);
1080  doc->appendChild(elemRoot);
1081 
1082 #ifdef DEBUG
1083  UINT32 debuglen = 3000;
1084  UINT8 debugout[3000];
1085  DOM_Output::dumpToMem(doc,debugout,&debuglen);
1086  debugout[debuglen] = 0;
1087  CAMsg::printMsg(LOG_DEBUG, "the AILogin Confirmation sent looks like this: %s \n",debugout);
1088 #endif
1089  sendSuccess = pAccInfo->pControlChannel->sendXMLMessage(doc);
1090  if (doc != NULL)
1091  {
1092  doc->release();
1093  doc = NULL;
1094  }
1095  return sendSuccess;
1096  }
1097 
1098 
1106 SINT32 CAAccountingInstance::processJapMessage(fmHashTableEntry * pHashEntry,const XERCES_CPP_NAMESPACE::DOMDocument* a_DomDoc)
1107  {
1108  INIT_STACK;
1109  BEGIN_STACK("CAAccountingInstance::processJapMessage");
1110 
1111  if (pHashEntry == NULL)
1112  {
1113  return E_UNKNOWN;
1114  }
1115 
1116  DOMElement* root = a_DomDoc->getDocumentElement();
1117  if(root == NULL)
1118  {
1119  CAMsg::printMsg(LOG_DEBUG, "ProcessJapMessage: getDocument Element is null!!!\n" );
1120  return E_UNKNOWN;
1121  }
1122  char* docElementName = XMLString::transcode(root->getTagName());
1123  SINT32 hf_ret = 0;
1124 
1125 
1126  // what type of message is it?
1127  if ( strcmp( docElementName, "AccountCertificate" ) == 0 )
1128  {
1129  #ifdef DEBUG
1130  CAMsg::printMsg( LOG_DEBUG, "Received an AccountCertificate. Calling handleAccountCertificate()\n" );
1131  #endif
1132  //handleFunc = &CAAccountingInstance::handleAccountCertificate;
1133  hf_ret = ms_pInstance->handleAccountCertificate( pHashEntry->pAccountingInfo, root );
1134  processJapMessageLoginHelper(pHashEntry, hf_ret, false);
1135  }
1136  else if ( strcmp( docElementName, "Response" ) == 0)
1137  {
1138  #ifdef DEBUG
1139  CAMsg::printMsg( LOG_DEBUG, "Received a Response (challenge-response)\n" );
1140  #endif
1141  //handleFunc = &CAAccountingInstance::handleChallengeResponse;
1142  hf_ret = ms_pInstance->handleChallengeResponse( pHashEntry->pAccountingInfo, root );
1143  processJapMessageLoginHelper(pHashEntry, hf_ret, false);
1144  /*if(hf_ret != CAXMLErrorMessage::ERR_OK)
1145  {
1146  unlockLogin(pHashEntry);
1147  }
1148  else*/
1149  if(hf_ret == (SINT32) CAXMLErrorMessage::ERR_OK)
1150  {
1151  //CAMsg::printMsg( LOG_DEBUG, "Prepaid bytes are: %d\n", getPrepaidBytes(pHashEntry->pAccountingInfo));
1152 
1153  if( (getPrepaidBytes(pHashEntry->pAccountingInfo) > 0) &&
1154  !(pHashEntry->pAccountingInfo->authFlags &
1156  {
1158  }
1159  }
1160  }
1161  else if ( strcmp( docElementName, "CC" ) == 0 )
1162  {
1163  #ifdef DEBUG
1164  CAMsg::printMsg( LOG_DEBUG, "Received a CC. Calling handleCostConfirmation()\n" );
1165  #endif
1166  //handleFunc = &CAAccountingInstance::handleCostConfirmation;
1167  hf_ret = ms_pInstance->handleCostConfirmation( pHashEntry->pAccountingInfo, root );
1168  processJapMessageLoginHelper(pHashEntry, hf_ret, true);
1169  /*if(hf_ret != CAXMLErrorMessage::ERR_OK)
1170  {
1171  unlockLogin(pHashEntry);
1172  }*/
1173  }
1174  else
1175  {
1176  CAMsg::printMsg( LOG_ERR,
1177  "AI Received XML message with unknown root element \"%s\". This is not accepted!\n",
1178  docElementName
1179  );
1180 
1181  SAVE_STACK("CAAccountingInstance::processJapMessage", "error");
1182  XMLString::release(&docElementName);
1183  return E_UNKNOWN;
1184  }
1185 
1186 
1187  XMLString::release(&docElementName);
1188 
1211  // remove these lines if AI thread pool is used (see @todo above)
1212  //(ms_pInstance->*handleFunc)(pHashEntry->pAccountingInfo, root );
1213 
1214  FINISH_STACK("CAAccountingInstance::processJapMessage");
1215  return E_SUCCESS;
1216  }
1217 
1219  UINT32 handlerReturnValue,
1220  bool lastLoginMessage)
1221 {
1222  if(pHashEntry->pAccountingInfo != NULL)
1223  {
1224  if(pHashEntry->pAccountingInfo->mutex == NULL)
1225  {
1226  return;
1227  }
1228  pHashEntry->pAccountingInfo->mutex->lock();
1230  {
1231  if(handlerReturnValue != CAXMLErrorMessage::ERR_OK)
1232  {
1235 
1236  CAXMLErrorMessage *err = NULL;
1237  XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
1238 
1239  /*if(pHashEntry->pAccountingInfo->authFlags & AUTH_BLOCKED )
1240  {
1241  err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED,
1242  (UINT8 *) "AI login: access denied because your account is blocked");
1243  }
1244  else if(pHashEntry->pAccountingInfo->authFlags & AUTH_ACCOUNT_EMPTY )
1245  {
1246  err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY,
1247  (UINT8 *) "AI login: access denied because your account is empty");
1248  }
1249  else if(pHashEntry->pAccountingInfo->authFlags & AUTH_INVALID_ACCOUNT )
1250  {
1251  err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_BALANCE,
1252  (UINT8 *) "AI login: access denied because your account is not valid");
1253  }
1254  else */ if(pHashEntry->pAccountingInfo->authFlags & AUTH_FAKE )
1255  {
1256  err = new CAXMLErrorMessage(handlerReturnValue);
1257 
1258  }
1259  else if(pHashEntry->pAccountingInfo->authFlags & AUTH_MULTIPLE_LOGIN )
1260  {
1262  (UINT8*)"You are already logged in.");
1263 
1264  }
1265  else
1266  {
1268  (UINT8 *) "AI login: error occured while connecting, access denied");
1269  }
1270 
1271 
1272  if(err != NULL)
1273  {
1274  err->toXmlDocument(errDoc);
1275  pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
1276  delete err;
1277  err = NULL;
1278  }
1279  if(errDoc != NULL)
1280  {
1281  errDoc->release();
1282  errDoc = NULL;
1283  }
1284  /*sendAILoginConfirmation(pHashEntry->pAccountingInfo,
1285  CAXMLErrorMessage::ERR_BLOCKED,
1286  (UINT8*) "AI access denied");*/
1287  }
1288  else if(lastLoginMessage)
1289  {
1290  //CAMsg::printMsg( LOG_ERR, "User successfully logged in\n");
1292  }
1293 
1294  }
1295  pHashEntry->pAccountingInfo->mutex->unlock();
1296  }
1297 }
1298 
1300 {
1301  SINT32 ret = 0;
1302  if(pHashEntry == NULL)
1303  {
1304  return ret |= AUTH_LOGIN_FAILED;
1305  }
1306  if(pHashEntry->pAccountingInfo == NULL)
1307  {
1308  return ret |= AUTH_LOGIN_FAILED;
1309  }
1310  if(pHashEntry->pAccountingInfo->mutex == NULL)
1311  {
1312  return ret |= AUTH_LOGIN_FAILED;
1313  }
1314  pHashEntry->pAccountingInfo->mutex->lock();
1315  ret = pHashEntry->pAccountingInfo->authFlags &
1317  pHashEntry->pAccountingInfo->mutex->unlock();
1318  return ret;
1319 }
1320 
1326 {
1327  SINT32 ret = 0;
1328  UINT64 accountNumber = 0;
1329  AccountLoginHashEntry *loginEntry;
1330  tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
1331 
1332  if(ms_pInstance==NULL)
1333  {
1334  return ret |= AUTH_LOGIN_FAILED;
1335  }
1337  {
1338  return ret |= AUTH_LOGIN_FAILED;
1339  }
1340  if(ms_pInstance->m_currentAccountsHashtable->getMutex() == NULL)
1341  {
1342  return ret |= AUTH_LOGIN_FAILED;
1343  }
1344  if(pHashEntry == NULL)
1345  {
1346  return ret |= AUTH_LOGIN_FAILED;
1347  }
1348  if(pHashEntry->pAccountingInfo == NULL)
1349  {
1350  return ret |= AUTH_LOGIN_FAILED;
1351  }
1352  if(pHashEntry->pAccountingInfo->mutex == NULL)
1353  {
1354  return ret |= AUTH_LOGIN_FAILED;
1355  }
1356  pAccInfo->mutex->lock();
1357  accountNumber = pAccInfo->accountNumber;
1358 
1359  //reset login flags
1361 
1362  if (!(pAccInfo->authFlags & AUTH_SETTLED_ONCE))
1363  {
1364  UINT32 statusCode = 0;
1366  if (dbInterface != NULL && dbInterface->getAccountStatus(accountNumber, statusCode) == E_SUCCESS)
1367  {
1368  if (statusCode > 0)
1369  {
1370  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Using DB status %u.\n",
1371  accountNumber, statusCode);
1372  }
1373  pAccInfo->authFlags |= statusCode;
1374  }
1375  else
1376  {
1377  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Could not fetch status from DB!.\n");
1378  }
1380  dbInterface = NULL;
1381  }
1382 
1383  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
1384  loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
1385 
1386  if (loginEntry)
1387  {
1388  if(loginEntry->authRemoveFlags)
1389  pAccInfo->authFlags &= ~(loginEntry->authRemoveFlags);
1390  pAccInfo->authFlags |= (loginEntry->authFlags & CRITICAL_SETTLE_FLAGS);
1391  }
1392  else
1393  {
1394  pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
1395  }
1396  /*ret = pHashEntry->pAccountingInfo->authFlags &
1397  (AUTH_LOGIN_NOT_FINISHED | AUTH_LOGIN_FAILED);*/
1398 
1399 
1400  CAXMLErrorMessage *err = NULL;
1401  XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
1402  /* Instead of using special login confirmation messages
1403  * we rather send XMLErrorMessages for backward compatibility reasons
1404  * because old JAPs (version <= 00.09.021) can handle them
1405  */
1406  if(pAccInfo->authFlags & AUTH_BLOCKED )
1407  {
1409  (UINT8 *) "AI login: access denied because your account is blocked");
1410  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems blocked.\n", accountNumber);
1411  }
1412  else if(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )
1413  {
1415  (UINT8 *) "AI login: access denied because your account is empty");
1416  if ((pAccInfo->authFlags & AUTH_SETTLED_ONCE))
1417  {
1418  pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
1419  if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
1420  {
1421  // this account is really empty; prevent an overflow in the prepaid bytes calculation
1422  pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
1423  }
1424  if (getPrepaidBytes(pAccInfo) > 0)
1425  {
1426  // the user may user his last bytes and is kicked out after that
1427  delete err;
1428  err = NULL;
1429  }
1430  }
1431  else
1432  {
1433  // TODO I am not sure whether this is enough; check this later
1434  loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
1435  pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
1436  }
1437  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems empty.\n", accountNumber);
1438  }
1439  else if(pAccInfo->authFlags & AUTH_INVALID_ACCOUNT )
1440  {
1442  (UINT8 *) "AI login: access denied because your account is not valid");
1443  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems invalid.\n", accountNumber);
1444  }
1445  else if(pAccInfo->authFlags & AUTH_UNKNOWN )
1446  {
1448  (UINT8 *) "AI login: error occured while connecting, access denied");
1449  CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Unknown error was found for account %llu.\n", accountNumber);
1450  }
1451 
1452  if(err != NULL)
1453  {
1454  err->toXmlDocument(errDoc);
1455  pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
1456  delete err;
1457  err = NULL;
1458  if(errDoc != NULL)
1459  {
1460  errDoc->release();
1461  errDoc = NULL;
1462  }
1463  ret |= AUTH_LOGIN_FAILED;
1464  }
1465  else
1466  {
1467 
1468  //send login confirmation to user, but if the message could not be send, login will fail
1469  /* These login confirmation messages are necessary for the new AI login protocol to indicate
1470  * that the process is finished after a settlement.
1471  * They won't bother old JAPs (version <= 00.09.021) because they will ignore
1472  * these confirmations.
1473  */
1474  if(sendAILoginConfirmation(pAccInfo,
1476  (UINT8*) "AI login successful") != E_SUCCESS)
1477  {
1478  ret |= AUTH_LOGIN_FAILED;
1479  }
1480  }
1481 
1482  /* unlock the loginEntry object for other login threads */
1483  //resetLoginOngoing(loginEntry, pHashEntry);
1484  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
1485  pAccInfo->mutex->unlock();
1486  return ret;
1487 }
1488 
1490 {
1491  return handleAccountCertificate_internal(pAccInfo, root);
1492 
1493  INIT_STACK;
1494  FINISH_STACK("CAAccountingInstance::handleAccountCertificate");
1495 }
1496 
1497 
1507  {
1508  INIT_STACK;
1509  BEGIN_STACK("CAAccountingInstance::handleAccountCertificate");
1510 
1511  //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate start\n");
1512 
1513  //CAMsg::printMsg(LOG_DEBUG, "started method handleAccountCertificate\n");
1514  DOMElement* elGeneral=NULL;
1515  timespec now;
1516  getcurrentTime(now);
1517 
1518  // check authstate of this user
1519  if (pAccInfo == NULL)
1520  {
1522  }
1523 
1524  pAccInfo->mutex->lock();
1525 
1526  if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
1527  {
1528  pAccInfo->mutex->unlock();
1530  }
1531 
1532  if (pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)
1533  {
1534  #ifdef DEBUG
1535  CAMsg::printMsg(LOG_DEBUG, "Already got an account cert. Ignoring...");
1536  #endif
1537  CAXMLErrorMessage err(
1539  (UINT8*)"You have already sent an Account Certificate"
1540  );
1541  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1542  err.toXmlDocument(errDoc);
1543  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
1544  if (errDoc != NULL)
1545  {
1546  errDoc->release();
1547  errDoc = NULL;
1548  }
1549  pAccInfo->mutex->unlock();
1551  }
1552 
1553  // parse & set accountnumber
1554  if (getDOMChildByName( root, "AccountNumber", elGeneral, false ) != E_SUCCESS ||
1555  getDOMElementValue( elGeneral, pAccInfo->accountNumber ) != E_SUCCESS)
1556  {
1557  CAMsg::printMsg( LOG_ERR, "AccountCertificate has wrong or no accountnumber. Ignoring...\n");
1559  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1560  err.toXmlDocument(errDoc);
1561  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
1562  if (errDoc != NULL)
1563  {
1564  errDoc->release();
1565  errDoc = NULL;
1566  }
1567  pAccInfo->mutex->unlock();
1569  }
1570 
1571  // parse & set payment instance id
1572  UINT32 len=256;
1573  pAccInfo->pstrBIID=new UINT8[256];
1574  if ( getDOMChildByName( root,"BiID", elGeneral, false ) != E_SUCCESS ||
1575  getDOMElementValue( elGeneral,pAccInfo->pstrBIID, &len ) != E_SUCCESS)
1576  {
1577  delete[] pAccInfo->pstrBIID;
1578  pAccInfo->pstrBIID = NULL;
1579  CAMsg::printMsg( LOG_ERR, "AccountCertificate has no Payment Instance ID. Ignoring...\n");
1581  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1582  err.toXmlDocument(errDoc);
1583  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
1584  if (errDoc != NULL)
1585  {
1586  errDoc->release();
1587  errDoc = NULL;
1588  }
1589  pAccInfo->mutex->unlock();
1591  }
1592  #ifdef DEBUG
1593  CAMsg::printMsg(LOG_DEBUG, "Stored payment instance ID: %s\n", pAccInfo->pstrBIID);
1594  #endif
1595 
1596 
1597  // parse & set public key
1598  if ( getDOMChildByName( root, "JapPublicKey", elGeneral, false ) != E_SUCCESS )
1599  {
1600  CAMsg::printMsg( LOG_ERR, "AccountCertificate contains no public key. Ignoring...\n");
1602  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1603  err.toXmlDocument(errDoc);
1604  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
1605  if (errDoc != NULL)
1606  {
1607  errDoc->release();
1608  errDoc = NULL;
1609  }
1610  pAccInfo->mutex->unlock();
1612  }
1613  #ifdef DEBUG
1614  UINT8* aij;
1615  UINT32 aijsize;
1616  aij = DOM_Output::dumpToMem(elGeneral, &aijsize);
1617  aij[aijsize-1]=0;
1618  CAMsg::printMsg( LOG_DEBUG, "Setting user public key %s>\n", aij );
1619  delete[] aij;
1620  aij = NULL;
1621  #endif
1622  pAccInfo->pPublicKey = new CASignature();
1623  if ( pAccInfo->pPublicKey->setVerifyKey( elGeneral ) != E_SUCCESS )
1624  {
1626  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1627  err.toXmlDocument(errDoc);
1628  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
1629  if (errDoc != NULL)
1630  {
1631  errDoc->release();
1632  errDoc = NULL;
1633  }
1634  pAccInfo->mutex->unlock();
1636  }
1637 
1638  //if ((!m_pJpiVerifyingInstance) ||
1639  //(m_pJpiVerifyingInstance->verifyXML( root, (CACertStore *)NULL ) != E_SUCCESS ))
1640  if(CAMultiSignature::verifyXML(root, CALibProxytest::getOptions()->getBI()->getCertificate()))
1641  {
1642  // signature invalid. mark this user as bad guy
1643  CAMsg::printMsg( LOG_INFO, "CAAccountingInstance::handleAccountCertificate(): Bad Jpi signature\n" );
1645  pAccInfo->mutex->unlock();
1647  }
1648 
1649 
1650  UINT8 * arbChallenge;
1651  UINT8 b64Challenge[ 512 ];
1652  UINT32 b64Len = 512;
1653 
1654  //CAMsg::printMsg(LOG_DEBUG, "Almost finished handleAccountCertificate, preparing challenge\n");
1655 
1656  // generate random challenge data and Base64 encode it
1657  arbChallenge = new UINT8[222];
1658  getRandom( arbChallenge, 222 );
1659  CABase64::encode( arbChallenge, 222, b64Challenge, &b64Len );
1660 
1661  delete[] pAccInfo->pChallenge;
1662  pAccInfo->pChallenge = arbChallenge; // store challenge for later..
1663 
1664  // generate XML challenge structure
1665  XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
1666  DOMElement* elemRoot = createDOMElement(doc, "Challenge" );
1667  DOMElement* elemPanic = createDOMElement(doc, "DontPanic" );
1668  DOMElement* elemPrepaid = createDOMElement(doc, "PrepaidBytes" );
1669  setDOMElementAttribute(elemPanic, "version",(UINT8*) "1.0" );
1670  doc->appendChild( elemRoot );
1671  elemRoot->appendChild( elemPanic );
1672  elemRoot->appendChild( elemPrepaid );
1673  setDOMElementValue( elemPanic, b64Challenge );
1674  SINT32 prepaidAmount = 0; //m_dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
1675 
1677 
1678  //TODO: this is not a good moment to send the prepaid-bytes to the JonDo.
1679  //we cannot be sure that the database contains a consistent value here.
1680  if(dbInterface != NULL)
1681  {
1682  prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
1684  dbInterface = NULL;
1685  }
1686 
1687 
1688  SINT32 prepaidIvalLowerBound = 0; //(-1*(SINT32)CALibProxytest::getOptions()->getPrepaidInterval()); /* EXPERIMENTAL: transmit negative prepaid bytes (but not less than -PREPAID_BYTES) */
1689  if (prepaidAmount < prepaidIvalLowerBound)
1690  {
1691  prepaidAmount = prepaidIvalLowerBound;
1692  }
1693  //CAMsg::printMsg( LOG_DEBUG, "handleAccountCertificate read %i prepaid bytes\n", prepaidAmount);
1694  setDOMElementValue( elemPrepaid, prepaidAmount);
1695 
1696  // send XML struct to Jap & set auth flags
1697  pAccInfo->pControlChannel->sendXMLMessage(doc);
1698  if (doc != NULL)
1699  {
1700  doc->release();
1701  doc = NULL;
1702  }
1704  pAccInfo->challengeSentSeconds = time(NULL);
1705  //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]);
1706 
1707  //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate stop\n");
1708 
1709 
1710  pAccInfo->mutex->unlock();
1712 }
1713 
1714 
1716 {
1717  return handleChallengeResponse_internal(pAccInfo, root);
1718  INIT_STACK;
1719  FINISH_STACK("CAAccountingInstance::handleChallengeResponse");
1720 }
1721 
1722 
1730 {
1731  INIT_STACK;
1732  BEGIN_STACK("CAAccountingInstance::handleChallengeResponse");
1733 
1734 
1735  //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse start\n");
1736 
1737 
1738  UINT8 decodeBuffer[ 512 ];
1739  UINT32 decodeBufferLen = 512;
1740  UINT32 usedLen;
1741  /* DOMElement* elemPanic=NULL;
1742  DSA_SIG * pDsaSig=NULL; */
1743  SINT32 prepaidAmount = 0;
1744  AccountLoginHashEntry* loginEntry;
1745  CAXMLCostConfirmation* pCC = NULL;
1746  bool bSendCCRequest = true;
1747  UINT32 status;
1748 
1749  // check current authstate
1750 
1751  if (pAccInfo == NULL)
1752  {
1754  }
1755 
1756  pAccInfo->mutex->lock();
1757 
1758  if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
1759  {
1760  pAccInfo->mutex->unlock();
1762  }
1763 
1764  if( (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)) ||
1765  (!(pAccInfo->authFlags & AUTH_CHALLENGE_SENT))
1766  )
1767  {
1768  pAccInfo->mutex->unlock();
1770  }
1771  pAccInfo->authFlags &= ~AUTH_CHALLENGE_SENT;
1772 
1773  // get raw bytes of response
1774  if ( getDOMElementValue( root, decodeBuffer, &decodeBufferLen ) != E_SUCCESS )
1775  {
1776  CAMsg::printMsg( LOG_DEBUG, "ChallengeResponse has wrong XML format. Ignoring\n" );
1777  pAccInfo->mutex->unlock();
1779  }
1780  DOMElement *elemClientVersion = NULL;
1781  getDOMChildByName(root, "ClientVersion", elemClientVersion, false);
1782  if(elemClientVersion != NULL)
1783  {
1784  UINT32 clientVersionStrLen = CLIENT_VERSION_STR_LEN;
1785  UINT8 *clientVersionStr = new UINT8[clientVersionStrLen];
1786  memset(clientVersionStr, 0, clientVersionStrLen);
1787  if( getDOMElementValue(elemClientVersion, clientVersionStr, &clientVersionStrLen) != E_SUCCESS)
1788  {
1789  delete [] clientVersionStr;
1790  clientVersionStr = NULL;
1791  }
1792 #ifdef DEBUG
1793  CAMsg::printMsg(LOG_DEBUG, "Client Version (account %llu): %s\n",
1794  pAccInfo->accountNumber,
1795  (clientVersionStr != NULL ? clientVersionStr : (UINT8*) "<not set>"));
1796 #endif
1797  pAccInfo->clientVersion = clientVersionStr;
1798  }
1799  else
1800  {
1801  pAccInfo->clientVersion = NULL;
1802  }
1803  decodeBuffer[decodeBufferLen] = 0;
1804 
1805  usedLen = decodeBufferLen;
1806  decodeBufferLen = 512;
1807  CABase64::decode( decodeBuffer, usedLen, decodeBuffer, &decodeBufferLen );
1808 
1809  /*
1810  UINT8 b64Challenge[ 512 ];
1811  UINT32 b64Len = 512;
1812  CABase64::encode(pHashEntry->pAccountingInfo->pChallenge, 222, b64Challenge, &b64Len);
1813  CAMsg::printMsg(LOG_DEBUG, "Challenge:\n%s\n", b64Challenge);
1814  */
1815 
1816  // check signature
1817  //pDsaSig = DSA_SIG_new();
1818  CASignature * sigTester = pAccInfo->pPublicKey;
1819  //sigTester->decodeRS( decodeBuffer, decodeBufferLen, pDsaSig );
1820  if ( sigTester->verifyDER( pAccInfo->pChallenge, 222, decodeBuffer, decodeBufferLen )
1821  != E_SUCCESS )
1822  {
1823  UINT8 accountNrAsString[32];
1824  print64(accountNrAsString, pAccInfo->accountNumber);
1825  CAMsg::printMsg(LOG_ERR, "Challenge-response authentication failed for account %s!\n", accountNrAsString);
1826  pAccInfo->authFlags |= AUTH_FAKE;
1827  pAccInfo->authFlags &= ~AUTH_ACCOUNT_OK;
1828  pAccInfo->mutex->unlock();
1830  }
1831 
1832  pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
1833 
1834  //EXPERIMENTAL NEW CODE for intercepting multiple login attempts
1835  m_currentAccountsHashtable->getMutex()->lock();
1836  loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
1837  struct t_fmhashtableentry *ownerRef = NULL;
1838  if(loginEntry != NULL) // (other) user (with same account) already logged in
1839  {
1840  ownerRef = loginEntry->ownerRef;
1841  if(ownerRef != NULL)
1842  {
1843  bool isLoginFree = testAndSetLoginOwner(loginEntry, ownerRef);
1844  //obtaining ownership and setting loginProcessOngoing also means to cleanup the
1845  //old login entry after the connection belonging to the old login is closed.
1846  //So it can be assured that no other login-thread will find a NULL entry at the above if-statement
1847  m_currentAccountsHashtable->getMutex()->unlock();
1848  //abort if another thread is logging in but ...
1849  if(!isLoginFree)
1850  {
1851  CAMsg::printMsg(LOG_DEBUG, "Exiting because login is occupied for owner %p of account %llu.\n", ownerRef);
1852  pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
1853  pAccInfo->mutex->unlock();
1855  }
1856  //...if the former login is finished and the connection is in use: force the previous login-connection to be kicked out.
1857  m_mix->getLoginMutex()->lock();
1859  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
1860  kickoutMsg.toXmlDocument(errDoc);
1861  //Note: the ownerRef hashEntry can already be cleared at that point.
1862  if( m_mix->forceKickout(ownerRef, errDoc) )
1863  {
1864  CAMsg::printMsg(LOG_DEBUG, "Kickout was requested for owner %p of account %llu, waiting...\n", ownerRef,
1865  pAccInfo->accountNumber);
1866  //Synchronize until the main thread can sure that the connection is closed. (After FirstMixA::checkConnections()
1867  // in main loop)
1868  //not dangerous if ensured that the cleanup notifier is always locked after loginCV
1869  //but it is necessary to lock cleanupNotifier before releasing loginCV. otherwise we might lose
1870  //the signal from cleanupNotifier. This can't happen if the main thread that
1871  //peforms the cleanup is still blokced by loginCV before it can acquire cleanupNotifier during the cleanup.
1872  ownerRef->cleanupNotifier->lock();
1873  m_mix->getLoginMutex()->unlock();
1874  ownerRef->cleanupNotifier->wait();
1875  ownerRef->cleanupNotifier->unlock();
1876  }
1877  else
1878  {
1879  m_mix->getLoginMutex()->unlock();
1880  //if the forceKickout returns false the ownerRef was already cleared.
1881  //no need to wait any further.
1882  CAMsg::printMsg(LOG_INFO, "ownerRef %p of account %llu already kicked out.\n", ownerRef, pAccInfo->accountNumber);
1883  }
1884  errDoc->release();
1885  errDoc = NULL;
1886  //obtain hashtable lock again.
1887  m_currentAccountsHashtable->getMutex()->lock();
1888  if(loginEntry != NULL)
1889  {
1890  //When login ownership was obtained: cleanup the former entry.
1891  CAMsg::printMsg(LOG_INFO, "finally cleaning up loginEntry %p for former owner %p of account %llu\n",
1892  loginEntry, loginEntry->ownerRef, pAccInfo->accountNumber);
1893  ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
1894  delete loginEntry->ownerLock;
1895  delete loginEntry;
1896  loginEntry = NULL;
1897  }
1898  }
1899  else
1900  {
1901  //Impossible or Bug
1902  CAMsg::printMsg(LOG_CRIT, "BUG: ownerRef of an active login entry MUST NOT be null. Please report.\n");
1903  m_currentAccountsHashtable->getMutex()->unlock();
1904  pAccInfo->mutex->unlock();
1906  }
1907  }
1908  //POST CONDITION: old login entry cleared.
1909  loginEntry = new AccountLoginHashEntry;
1910  loginEntry->accountNumber = pAccInfo->accountNumber;
1911  loginEntry->count = 1;
1912  loginEntry->confirmedBytes = 0;
1913  loginEntry->authRemoveFlags = 0;
1914  loginEntry->authFlags = 0;
1915  loginEntry->userID = pAccInfo->userID;
1916  loginEntry->ownerRef = pAccInfo->ownerRef;
1917  loginEntry->loginOngoing = true;
1918  loginEntry->ownerLock = new CAMutex();
1919  m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
1920 
1921  //m_currentAccountsHashtable->getMutex()->unlock();
1922 
1923  // fetch cost confirmation from last session if available, and retrieve information; synchronized with settle thread
1924  bool bSettled;
1926 #ifdef DEBUG
1927  CAMsg::printMsg(LOG_DEBUG, "Checking database for previously prepaid bytes...\n");
1928 #endif
1929 
1930  if(dbInterface != NULL)
1931  {
1932  prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
1933  dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC, bSettled);
1934  }
1935  else
1936  {
1937  prepaidAmount = 0;
1938  }
1939 
1940 
1941  if (pCC != NULL)
1942  {
1943  if(!cascadeMatchesCC(pCC))
1944  {
1945  delete pCC;
1946  pCC = NULL;
1947  CAMsg::printMsg(LOG_INFO, "CC do not match current Cascade. Discarding CC.\n");
1948  }
1949  }
1950 
1951  if (pCC != NULL)
1952  {
1953  if (bSettled)
1954  {
1956  }
1957 #ifdef DEBUG
1958  CAMsg::printMsg(LOG_DEBUG, "pAccInfo->transferredBytes is %llu, confirmedBytes: %llu, pCC->transferredBytes is %llu\n",
1959  pAccInfo->transferredBytes, pAccInfo->confirmedBytes, pCC->getTransferredBytes());
1960 #endif
1961  pAccInfo->transferredBytes += pCC->getTransferredBytes();
1962  pAccInfo->confirmedBytes = pCC->getTransferredBytes();
1963  #ifdef DEBUG
1964  UINT8 tmp[32];
1965  print64(tmp,pAccInfo->transferredBytes);
1966  CAMsg::printMsg(LOG_DEBUG, "Setting confirmedBytes to %llu, pAccInfo->transferredBytes is now %s\n",
1967  pAccInfo->confirmedBytes, tmp);
1968  #endif
1969  //delete pCC;
1970  }
1971  else
1972  {
1973  UINT8 tmp[32];
1974  print64(tmp,pAccInfo->accountNumber);
1975  CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cost confirmation for account %s not found in database. This seems to be a new user.\n", tmp);
1976  }
1977 
1979  //pAccInfo->mutex->unlock();
1980 // m_currentAccountsHashtable->getMutex()->lock();
1981 // pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
1982 //
1983 // loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
1984 // //now loginEntry == NULL must be asserted
1985 // if (!loginEntry)
1986 // {
1987 // // remember that this user is logged in at least once
1988 // loginEntry = new AccountLoginHashEntry;
1989 // loginEntry->accountNumber = pAccInfo->accountNumber;
1990 // loginEntry->count = 1;
1991 // loginEntry->confirmedBytes = 0;
1992 // loginEntry->authRemoveFlags = 0;
1993 // loginEntry->authFlags = 0;
1994 // loginEntry->userID = pAccInfo->userID;
1995 // m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
1996 // if (!(AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber)))
1997 // {
1998 // UINT8 accountNrAsString[32];
1999 // print64(accountNrAsString, pAccInfo->accountNumber);
2000 // CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Could not insert login entry for account %s!", accountNrAsString);
2001 // }
2002 // }
2003 // else
2004 // {
2005 // loginEntry->count++;
2006 // }
2007 // if (loginEntry->count > 1)
2008 // {
2009 // /*
2010 // * There already is a user logged in with this account.
2011 // */
2012 // UINT8 accountNrAsString[32];
2013 // print64(accountNrAsString, pAccInfo->accountNumber);
2014 // if (loginEntry->count < MAX_TOLERATED_MULTIPLE_LOGINS)
2015 // {
2016 // // There is now more than one user logged in with this account; kick out the other users!
2017 // CAMsg::printMsg(LOG_INFO,
2018 // "CAAccountingInstance: Multiple logins (%d) of user with account %s detected! Kicking out other users with this account...\n",
2019 // loginEntry->count, accountNrAsString);
2020 // loginEntry->userID = pAccInfo->userID; // this is the current user; kick out the others
2021 // }
2022 // else
2023 // {
2024 // /* The maximum of tolerated concurrent logins for this user is exceeded.
2025 // * He won't get any new access again before the old connections have been closed!
2026 // * @mod: in this case not more than one login is allowed at a time. The User has to wait until
2027 // * the old login will be deleted.
2028 // */
2029 // CAMsg::printMsg(LOG_INFO,
2030 // "CAAccountingInstance: Maximum of multiple logins exceeded (%d) for user with account %s! Kicking out this user!\n",
2031 // loginEntry->count, accountNrAsString);
2032 // bSendCCRequest = false; // not needed...
2033 // pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
2034 //
2035 // delete pCC;
2036 // pCC = NULL;
2037 // m_currentAccountsHashtable->getMutex()->unlock();
2038 // pAccInfo->mutex->unlock();
2039 // return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
2040 // }
2041 // }
2042 
2043  UINT8 tmp[32];
2044  print64(tmp,pAccInfo->accountNumber);
2045  if (prepaidAmount > 0)
2046  {
2047  CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Got %d prepaid bytes for account nr. %s.\n",prepaidAmount, tmp);
2048 
2049  //pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
2050 
2051  if (pAccInfo->transferredBytes >= (UINT32)prepaidAmount)
2052  {
2053  pAccInfo->transferredBytes -= prepaidAmount;
2054  }
2055  else
2056  {
2057  UINT8 tmp2[32];
2058  print64(tmp2, pAccInfo->transferredBytes);
2059  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Transferred bytes of %s for account %s are lower than prepaid amount! "
2060  "Maybe we lost a CC?\n",tmp2, tmp);
2061  prepaidAmount = 0;
2062  }
2063  }
2064  else
2065  {
2066  prepaidAmount = 0;
2067  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: No database record for prepaid bytes found for account nr. %s.\n", tmp);
2068  }
2069  //CAMsg::printMsg(LOG_DEBUG, "Number of prepaid (confirmed-transferred) bytes : %d \n",pAccInfo->confirmedBytes-pAccInfo->transferredBytes);
2070 
2076  SINT32 dbRet;
2077  if(dbInterface != NULL);
2078  {
2079  dbRet = dbInterface->getAccountStatus(pAccInfo->accountNumber, status);
2081  dbInterface = NULL;
2082  }
2083 
2084  if (dbRet != E_SUCCESS)
2085  {
2086  UINT8 tmp[32];
2087  print64(tmp,pAccInfo->accountNumber);
2088  CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Could not check status for account %s!\n", tmp);
2089  }
2090  else if (status > CAXMLErrorMessage::ERR_OK)
2091  {
2092  //UINT32 authFlags = 0;
2093  //the auth flags are set after this check, but they need to be verified during a forced settlement
2094  //at the end of the login. (see finishLoginProcess())
2095  CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Illegal status %u for account %llu found.\n",
2096  status, pAccInfo->accountNumber);
2097  if (status == CAXMLErrorMessage::ERR_BLOCKED)
2098  {
2099  pAccInfo->authFlags |= AUTH_BLOCKED;
2100  }
2101  else if (status == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
2102  {
2103  pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
2104  }
2105  else if (status == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
2106  {
2107  pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
2108  }
2109 
2110  /*if (authFlags)
2111  {
2112  pAccInfo->authFlags |= AUTH_BLOCKED;
2113  if (loginEntry->confirmedBytes == 0)
2114  {
2115  loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
2116  }
2117  }*/
2118  }
2119  m_currentAccountsHashtable->getMutex()->unlock();
2120 
2122  //pAccInfo->mutex->lock();
2123  SINT32 sendStatus = E_SUCCESS;
2124  if (bSendCCRequest)
2125  {
2126  // fetch cost confirmation from last session if available, and send it
2127  //CAXMLCostConfirmation * pCC = NULL;
2128  //m_dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC);
2129  if(pCC != NULL)
2130  {
2131 #ifdef DEBUG
2132  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Sending pcc to sign with %llu transferred bytes\n", pCC->getTransferredBytes());
2133 #endif
2134  // the typical case; the user had logged in before
2135  /* there shouldn't be any counting synchronisation problems with the JAP
2136  * because the new login protocol doesn't permit JAPs
2137  * to exchange data before login is finished.
2138  */
2140  pAccInfo->bytesToConfirm = (prepaidIval - prepaidAmount) + pCC->getTransferredBytes();
2141 #ifdef DEBUG
2142  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before CC request, bytesToConfirm: %llu, prepaidIval: %u, "
2143  "prepaidAmount: %d, transferred bytes: %llu\n",
2144  pAccInfo->bytesToConfirm, prepaidIval, prepaidAmount, pAccInfo->transferredBytes);
2145 
2146 #endif
2147  if( (pAccInfo->clientVersion == NULL) ||
2148  (strncmp((char*)pAccInfo->clientVersion, PREPAID_PROTO_CLIENT_VERSION, CLIENT_VERSION_STR_LEN) < 0) )
2149  {
2150  //old CC without payRequest and prepaid bytes.
2151  //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: Old prepaid proto version.\n", pAccInfo->accountNumber);
2152  sendStatus = pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
2153 
2154  }
2155  else
2156  {
2157  //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: New prepaid proto version. prepaid bytes: %d\n",
2158  // pAccInfo->accountNumber, prepaidAmount);
2159  sendStatus = sendInitialCCRequest(pAccInfo, pCC, prepaidAmount);
2160  }
2161  }
2162  else
2163  {
2164  // there is no CC in the database; typically this is the first connection of this user
2165  if (prepaidAmount > 0)
2166  {
2167  // Delete any previously stored prepaid amount; there should not be any! CC lost?
2168  pAccInfo->transferredBytes += prepaidAmount;
2169  }
2170  sendStatus = sendCCRequest(pAccInfo);
2171  }
2172  }
2173 
2174 
2175  delete pCC;
2176  pCC = NULL;
2177 
2178 
2179  if ( pAccInfo->pChallenge != NULL ) // free mem
2180  {
2181  delete[] pAccInfo->pChallenge;
2182  pAccInfo->pChallenge = NULL;
2183  }
2184  //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse stop\n");
2185 
2186  pAccInfo->mutex->unlock();
2187  if(sendStatus == E_SUCCESS)
2188  {
2190  }
2191  else
2192  {
2194  }
2195 }
2196 
2198 {
2199  return handleCostConfirmation_internal(pAccInfo, root);
2200  INIT_STACK;
2201  FINISH_STACK("CAAccountingInstance::handleCostConfirmation");
2202 }
2203 
2208 {
2209  INIT_STACK;
2210  BEGIN_STACK("CAAccountingInstance::handleCostConfirmation");
2211 
2212  if (pAccInfo == NULL)
2213  {
2215  }
2216 
2217  pAccInfo->mutex->lock();
2218 
2219  if ( (pAccInfo->authFlags & AUTH_DELETE_ENTRY) ||
2220  (!(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED ) && (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )) )
2221  {
2222  CAMsg::printMsg(LOG_ERR,
2223  "CAAccountingInstance::handleCostConfirmation Ignoring CC, restricted flags set: %s %s\n",
2224  ((pAccInfo->authFlags & AUTH_DELETE_ENTRY) ? "AUTH_DELETE_ENTRY" : "") ,
2225  ((pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY) ? "AUTH_ACCOUNT_EMPTY" : ""));
2226  // ignore CCs for this account!
2227  pAccInfo->mutex->unlock();
2229  }
2230 
2231  // check authstate
2232  if (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
2233  !(pAccInfo->authFlags & AUTH_ACCOUNT_OK) ||
2234  !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST))
2235  {
2236  CAMsg::printMsg(LOG_ERR,
2237  "CAAccountingInstance::handleCostConfirmation CC was received but has not been requested! Ignoring...\n");
2238 
2239  pAccInfo->mutex->unlock();
2241  }
2242 
2243  CAXMLCostConfirmation* pCC = CAXMLCostConfirmation::getInstance(root);
2244  if(pCC==NULL)
2245  {
2246  pAccInfo->mutex->unlock();
2248  }
2249 
2250  // for debugging only: test signature the oldschool way
2251  // warning this removes the signature from doc!!!
2252  if (pAccInfo->pPublicKey==NULL||
2253  pAccInfo->pPublicKey->verifyXML( root ) != E_SUCCESS)
2254  {
2255  // wrong signature
2256  CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
2257  CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
2258  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
2259  err.toXmlDocument(errDoc);
2260  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
2261  if (errDoc != NULL)
2262  {
2263  errDoc->release();
2264  errDoc = NULL;
2265  }
2266  delete pCC;
2267  pCC = NULL;
2268  pAccInfo->mutex->unlock();
2270  }
2271  #ifdef DEBUG
2272  else
2273  {
2274  CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
2275  }
2276  #endif
2277 
2278 
2279  if (pCC->getNumberOfHashes() != m_allHashesLen)
2280  {
2281  CAMsg::printMsg( LOG_INFO, "CostConfirmation has illegal number of price cert hashes!\n" );
2283  (UINT8*)"CostConfirmation has illegal number of price cert hashes");
2284  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
2285  err.toXmlDocument(errDoc);
2286  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
2287  if (errDoc != NULL)
2288  {
2289  errDoc->release();
2290  errDoc = NULL;
2291  }
2292  delete pCC;
2293  pCC = NULL;
2294  pAccInfo->mutex->unlock();
2296  }
2297 
2298  /*Hashtable* certHashCC =
2299  new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
2300  UINT8* certHash;*/
2301  //bool bFailed = false;
2302  //for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
2303  //{
2304  // certHash = pCC->getPriceCertHash(i);
2305  // certHashCC->put(certHash, certHash);
2306  /*
2307  if ((certHash = (UINT8*)certHashCC->getValue(certHash)) != NULL)
2308  {
2309  CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
2310  }*/
2311  //}
2312  //for (UINT32 i = 0; i < m_allHashesLen; i++)
2313  //{
2314  //CAMsg::printMsg( LOG_INFO, "CA: %s\n", m_allHashes[i]);
2315  // certHash = (UINT8*)certHashCC->remove(m_allHashes[i]);
2316  // if (certHash == NULL)
2317  // {
2318  // bFailed = true;
2319  // break;
2320  // }
2321  // else
2322  // {
2323  // delete[] certHash;
2324  // }
2325  //}
2326  //certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
2327  //delete certHashCC;
2328 
2329  if (!cascadeMatchesCC(pCC))
2330  {
2331  CAMsg::printMsg( LOG_INFO, "CostConfirmation has invalid price cert hashes!\n" );
2333  (UINT8*)"CostConfirmation has invalid price cert hashes");
2334  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
2335  err.toXmlDocument(errDoc);
2336  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
2337  if (errDoc != NULL)
2338  {
2339  errDoc->release();
2340  errDoc = NULL;
2341  }
2342  delete pCC;
2343  pCC = NULL;
2344  pAccInfo->mutex->unlock();
2346  }
2347 
2348 
2349 
2350  // parse & set transferredBytes
2351  //when using Prepayment, this check is outdated, but left in to notice the most crude errors/cheats
2352  //The CC's transferredBytes should be equivalent to
2353  //AccInfo's confirmed bytes + the Config's PrepaidInterval - the number of bytes transferred between
2354  //requesting and receiving the CC
2355 #ifdef DEBUG
2356  CAMsg::printMsg( LOG_DEBUG, "received cost confirmation for %llu transferred bytes where confirmed bytes are %llu, we need %llu bytes to confirm"
2357  ", mix already counted %llu transferred bytes\n",
2358  pCC->getTransferredBytes(), pAccInfo->confirmedBytes, pAccInfo->bytesToConfirm,
2359  pAccInfo->transferredBytes);
2360 #endif
2361 
2362  if(pCC->getTransferredBytes() > (pAccInfo->transferredBytes+CALibProxytest::getOptions()->getPrepaidInterval()) )
2363  {
2364  CAMsg::printMsg( LOG_ERR, "Warning: ignoring this CC for account %llu "
2365  "because it tries to confirm %lld prepaid bytes where only %u prepaid bytes are allowed (cc->tranferredbytes: %llu, accInfo->tranferredBytes: %llu)\n",
2366  pAccInfo->accountNumber, (pCC->getTransferredBytes() - pAccInfo->transferredBytes),
2368  pCC->getTransferredBytes(), pAccInfo->transferredBytes);
2369 
2371  (UINT8*)"More bytes confirmed than allowed.");
2372  XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
2373  err.toXmlDocument(errDoc);
2374  pAccInfo->pControlChannel->sendXMLMessage(errDoc);
2375  if (errDoc != NULL)
2376  {
2377  errDoc->release();
2378  errDoc = NULL;
2379  }
2380  //mark as account empty has the effect is that the user can empty his prepaid amount and then will be kicked out.
2381  pAccInfo->authFlags |= AUTH_FAKE;
2382  delete pCC;
2383  pCC = NULL;
2384  pAccInfo->mutex->unlock();
2386  }
2387 
2388  if (pCC->getTransferredBytes() < pAccInfo->confirmedBytes)
2389  {
2390 
2391  CAMsg::printMsg( LOG_ERR, "CostConfirmation has insufficient number of bytes:\n");
2392  CAMsg::printMsg( LOG_ERR, "CC->transferredBytes: %llu < confirmedBytesBytes: %llu\n", pCC->getTransferredBytes(), pAccInfo->confirmedBytes);
2393 
2394  if(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
2395  {
2396  //@todo: perhaps we should use another flag to indicate that this user should be kicked out.
2397  pAccInfo->authFlags |= AUTH_FAKE;
2398  delete pCC;
2399  pCC = NULL;
2400  pAccInfo->mutex->unlock();
2402  }
2403 
2404  /*
2405  CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
2406  (UINT8*)"Your CostConfirmation has a wrong number of transferred bytes");
2407  DOM_Document errDoc;
2408  err.toXmlDocument(errDoc);
2409  pAccInfo->pControlChannel->sendXMLMessage(errDoc);*/
2410  }
2411  else if (pCC->getTransferredBytes() == pAccInfo->confirmedBytes && getPrepaidBytes(pAccInfo) != CALibProxytest::getOptions()->getPrepaidInterval())
2412  {
2413  CAMsg::printMsg(LOG_WARNING, "Received CostConfirmation for account %llu has no difference in bytes to current CC (%llu bytes).\n",
2414  pAccInfo->accountNumber, pCC->getTransferredBytes());
2415  }
2416  else
2417  {
2418  /*
2419  UINT8 tmp[32];
2420  print64(tmp,pCC->getTransferredBytes());
2421  CAMsg::printMsg( LOG_ERR, "Transferredbytes in CC: %s\n", tmp);
2422  */
2423  SINT32 dbRet = E_UNKNOWN;
2425  if(dbInterface != NULL)
2426  {
2427  dbRet = dbInterface->storeCostConfirmation(*pCC, m_currentCascade);
2429  dbInterface = NULL;
2430  }
2431  if (dbRet != E_SUCCESS)
2432  {
2433  UINT8 tmp[32];
2434  print64(tmp,pCC->getAccountNumber());
2435  CAMsg::printMsg( LOG_INFO, "CostConfirmation for account %s could not be stored in database!\n", tmp );
2436  pAccInfo->authFlags |= AUTH_DATABASE;
2437  }
2438  else
2439  {
2440 #ifdef DEBUG
2441  CAMsg::printMsg( LOG_INFO, "Handle CC: pCC->transBytes: %llu\n", pCC->getTransferredBytes() );
2442 #endif
2443  pAccInfo->confirmedBytes = pCC->getTransferredBytes();
2444 
2446  {
2447  // initiate immediate settling
2448 #ifdef DEBUG
2449  UINT64 currentMillis;
2450  UINT8 tmpStrCurrentMillis[50];
2451  getcurrentTimeMillis(currentMillis);
2452  print64(tmpStrCurrentMillis,currentMillis);
2453  CAMsg::printMsg(LOG_DEBUG, "AccountingSettleThread: Settle ini: %s\n", tmpStrCurrentMillis);
2454 #endif
2456 
2457  }
2458  }
2459  }
2460 #ifdef DEBUG
2461  CAMsg::printMsg(LOG_ERR, "Handle CC request: pAccInfo->confirmedBytes: %llu, ppAccInfo->transferredBytes: %llu\n",
2462  pAccInfo->confirmedBytes, pAccInfo->transferredBytes);
2463 #endif
2464  if (pAccInfo->confirmedBytes >= pAccInfo->bytesToConfirm)
2465  {
2466  // the user confirmed everything we wanted; if a timeout has been set, it should be reset
2467  pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
2468  pAccInfo->lastHardLimitSeconds = time(NULL);
2469  }
2470  else
2471  {
2472  /*UINT8 tmp[32], tmp2[32], tmp3[32];
2473  print64(tmp, pCC->getTransferredBytes());
2474  print64(tmp2, pCC->getAccountNumber());
2475  print64(tmp3, pAccInfo->bytesToConfirm);*/
2476  CAMsg::printMsg(LOG_ERR, "AccountingSettleThread: Requested CC value has NOT been confirmed by account nr %llu! "
2477  "Received Bytes: %llu/%llu "
2478  "Client should not be allowed to login.\n",
2479  pCC->getAccountNumber(),
2480  pCC->getTransferredBytes(),
2481  pAccInfo->bytesToConfirm);
2482 
2483  if(pAccInfo->authFlags & AUTH_LOGIN_SKIP_SETTLEMENT)
2484  {
2485  CAMsg::printMsg( LOG_INFO, "Skip settlement revoked.\n");
2486  pAccInfo->authFlags &= ~AUTH_LOGIN_SKIP_SETTLEMENT;
2487  }
2488  /*delete pCC;
2489  pCC = NULL;
2490  pAccInfo->mutex->unlock();
2491  pAccInfo->authFlags |= AUTH_FAKE;
2492  return CAXMLErrorMessage::ERR_WRONG_DATA;*/
2493  //m_pSettleThread->settle();
2494 
2495  }
2496 
2497  pAccInfo->bytesToConfirm = 0;
2498  pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
2499 
2500  delete pCC;
2501  pCC = NULL;
2502  pAccInfo->mutex->unlock();
2503 
2505 }
2506 
2512 {
2513  INIT_STACK;
2514  BEGIN_STACK("CAAccountingInstance::initTableEntry");
2515 
2516  //ms_pInstance->m_pMutex->lock();
2517 
2518  if (pHashEntry == NULL)
2519  {
2520  FINISH_STACK("CAAccountingInstance::initTableEntry:NULL");
2521  return E_UNKNOWN;
2522  }
2523 
2524  pHashEntry->pAccountingInfo = new tAiAccountingInfo;
2525  memset( pHashEntry->pAccountingInfo, 0, sizeof( tAiAccountingInfo ) );
2526 
2527  SAVE_STACK("CAAccountingInstance::initTableEntry", "After memset");
2528 
2529  pHashEntry->pAccountingInfo->authFlags =
2532  AUTH_SENT_CC_REQUEST | AUTH_LOGIN_NOT_FINISHED; // prevents multiple CC requests on login
2533  pHashEntry->pAccountingInfo->authTimeoutStartSeconds = time(NULL);
2534  pHashEntry->pAccountingInfo->lastHardLimitSeconds = time(NULL);
2535  pHashEntry->pAccountingInfo->sessionPackets = 0;
2536  pHashEntry->pAccountingInfo->transferredBytes = 0;
2537  pHashEntry->pAccountingInfo->confirmedBytes = 0;
2538  pHashEntry->pAccountingInfo->bytesToConfirm = 0;
2539  pHashEntry->pAccountingInfo->nrInQueue = 0;
2540  pHashEntry->pAccountingInfo->userID = pHashEntry->id;
2541  pHashEntry->pAccountingInfo->ownerRef = pHashEntry;
2542  pHashEntry->pAccountingInfo->clientVersion = NULL;
2543  pHashEntry->pAccountingInfo->mutex = new CAMutex;
2544  //ms_pInstance->m_pMutex->unlock();
2545 
2546 
2547  FINISH_STACK("CAAccountingInstance::initTableEntry");
2548 
2549  return E_SUCCESS;
2550 }
2551 
2552 
2553 
2560  {
2561  INIT_STACK;
2562  BEGIN_STACK("CAAccountingInstance::cleanupTableEntry");
2563 
2564  //ms_pInstance->m_pMutex->lock();
2565  tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
2566  AccountLoginHashEntry* loginEntry;
2567  SINT32 prepaidBytes = 0;
2568  SINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
2569 
2570  if (pAccInfo == NULL)
2571  {
2572  SAVE_STACK("CAAccountingInstance::cleanupTableEntry", "acc info null");
2573  //ms_pInstance->m_pMutex->unlock();
2574  return E_UNKNOWN;
2575  }
2576 
2577  //pAccInfo->mutex->lock();
2578 
2579  pHashEntry->pAccountingInfo=NULL;
2580 
2581  if (pAccInfo->accountNumber)
2582  {
2583  CAMsg::printMsg(LOG_INFO, "cleaning up entry %p of accountno. %llu (pAccInfo ref: %p)\n",
2584  pHashEntry, pAccInfo->accountNumber, pAccInfo);
2585  if (pAccInfo->authFlags & AUTH_ACCOUNT_OK)
2586  {
2587  // remove login
2588  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
2589  loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
2590 
2591  if (loginEntry)
2592  {
2593  // test: delete CC!!!
2594  //ms_pInstance->m_dbInterface->deleteCC(pAccInfo->accountNumber, ms_pInstance->m_currentCascade);
2595  if (testLoginEntryOwner(loginEntry, pHashEntry))// &&
2597  {
2598  if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
2599  {
2600  // make sure to store the correct number of prepaid bytes
2601  pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
2602  }
2603  //store prepaid bytes in database, so the user wont lose the prepaid amount by disconnecting
2604  prepaidBytes = getPrepaidBytes(pAccInfo);
2605  if (prepaidBytes > 0)
2606  {
2607  if (prepaidBytes > prepaidInterval)
2608  {
2609  UINT8 tmp[32];
2610  print64(tmp, pAccInfo->accountNumber);
2611  /* Client paid more than the prepaid interval -
2612  * this is beyond specification and not allowed!
2613  */
2614  CAMsg::printMsg(LOG_ERR,
2615  "PrepaidBytes of %d for account %s are higher than prepaid interval! "
2616  "The client (owner %x) did not behave according to specification. "
2617  "Deleting prepaid bytes!\n", prepaidBytes, tmp, pHashEntry);
2618  //"Deleting %d bytes...\n", prepaidBytes, tmp, pHashEntry, prepaidBytes - prepaidInterval);
2619 
2620  //prepaidBytes = prepaidInterval;
2621  prepaidBytes = 0;
2622  }
2623  }
2624 
2625  /*if (ms_pInstance->m_dbInterface)
2626  {
2627  ms_pInstance->m_dbInterface->storePrepaidAmount(pAccInfo->accountNumber,prepaidBytes, ms_pInstance->m_currentCascade);
2628  }*/
2630  if(dbInterface != NULL)
2631  {
2632  dbInterface->storePrepaidAmount(pAccInfo->accountNumber,
2633  prepaidBytes,
2636  dbInterface = NULL;
2637  }
2638  if(!isLoginOngoing(loginEntry, pHashEntry))
2639  {
2640  ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
2641  delete loginEntry->ownerLock;
2642  delete loginEntry;
2643  loginEntry = NULL;
2644  }
2645  else
2646  {
2647  CAMsg::printMsg(LOG_INFO, "Cleaning: Leaving loginEntry %x cleanup of owner %x to the next owner due to double-login of a user.\n",
2648  loginEntry, loginEntry->ownerRef);
2649  }
2650  }
2651 
2652  /*if (loginEntry->count <= 1)
2653  {
2654  if (loginEntry->count < 1)
2655  {
2656  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup found non-positive number of user login hash entries (%d)!\n", loginEntry->count);
2657  }
2658  // this is the last active user connection; delete the entry
2659  ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
2660  delete loginEntry->ownerLock;
2661  delete loginEntry;
2662  loginEntry = NULL;
2663  }
2664  else
2665  {
2666  // there are other connections from this user
2667  loginEntry->count--;
2668  }*/
2669  }
2670  else
2671  {
2672  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup did not find user login hash entry!\n");
2673  }
2674  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
2675  }
2676  }
2677  else
2678  {
2679  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Cleanup method found account zero.\n");
2680  }
2681 
2682  //free memory of pAccInfo
2683 
2684  delete pAccInfo->pPublicKey;
2685  pAccInfo->pPublicKey = NULL;
2686 
2687 
2688  delete [] pAccInfo->pChallenge;
2689  pAccInfo->pChallenge = NULL;
2690 
2691  delete [] pAccInfo->pstrBIID;
2692  pAccInfo->pstrBIID = NULL;
2693 
2694  delete [] pAccInfo->clientVersion;
2695  pAccInfo->clientVersion = NULL;
2696 
2697  pHashEntry->pAccountingInfo=NULL;
2698 
2699  if (pAccInfo->nrInQueue > 0)
2700  {
2701  /*
2702  if (pAccInfo->accountNumber == 0)
2703  {
2704  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for account zero: %u!\n", pAccInfo->nrInQueue);
2705  }
2706  else if (!(pAccInfo->authFlags & AUTH_ACCOUNT_OK))
2707  {
2708  UINT8 accountNrAsString[32];
2709  print64(accountNrAsString, pAccInfo->accountNumber);
2710  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for unauthorized account %s: %u!\n", accountNrAsString, pAccInfo->nrInQueue);
2711  }
2712  else*/
2713  {
2714  // there are still entries in the ai queue; empty it before deletion; we cannot delete it now
2715  pAccInfo->authFlags |= AUTH_DELETE_ENTRY;
2716  }
2717  }
2718  else if (pAccInfo->nrInQueue < 0)
2719  {
2720  CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup method found negative handle queue!\n");
2721  }
2722  //pAccInfo->mutex->unlock();
2723 
2724  if (!(pAccInfo->authFlags & AUTH_DELETE_ENTRY))
2725  {
2726  // there are no handles for this entry in the queue, we can savely delete it now
2727  delete pAccInfo->mutex;
2728  pAccInfo->mutex = NULL;
2729  delete [] pAccInfo->clientVersion;
2730  pAccInfo->clientVersion = NULL;
2731 
2732 #ifdef LOG_CRIME
2733  UINT64 accountNumber = pAccInfo->accountNumber;
2734  UINT64* surveillanceAccounts = CALibProxytest::getOptions()->getCrimeSurveillanceAccounts();
2735  UINT32 nrOfSurveillanceAccounts = CALibProxytest::getOptions()->getNrOfCrimeSurveillanceAccounts();
2736  const UINT8* peerIP = pHashEntry->peerIP;
2737 
2738  for (UINT32 iAccount = 0; iAccount < nrOfSurveillanceAccounts; iAccount++)
2739  {
2740  if (accountNumber == surveillanceAccounts[iAccount])
2741  {
2742  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]);
2743  break;
2744  }
2745  }
2746 #endif
2747 
2748  delete pAccInfo;
2749  pAccInfo = NULL;
2750  }
2751  else
2752  {
2753  CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cleanup method sent account deletion request to AI thread!\n");
2754  }
2755  //ms_pInstance->m_pMutex->unlock();
2756 
2757  FINISH_STACK("CAAccountingInstance::cleanupTableEntry");
2758 
2759  return E_SUCCESS;
2760  }
2761 
2763 {
2764  UINT32 settledCCs = 0;
2765  SINT32 retVal;
2766  do
2767  {
2768  retVal = __newSettlementTransaction(&settledCCs);
2769  }
2770  while(settledCCs >= MAX_SETTLED_CCS && retVal == E_SUCCESS);
2771  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!
2772 }
2773 
2775 {
2776 
2777  CAXMLErrorMessage **pErrMsgs = NULL, *settleException = NULL;
2778  CAXMLCostConfirmation **allUnsettledCCs = NULL;
2779  SettleEntry *entry = NULL, *nextEntry = NULL;
2780  CAAccountingDBInterface *dbInterface = NULL;
2781 
2782  UINT32 nrOfCCs = 0, i = 0;
2783  SINT32 biConnectionStatus = 0, ret = E_SUCCESS;
2784  UINT64 myWaitNr = 0;
2785 
2786 
2787  //settlement transactions need to be synchronized globally because the settlement thread as well as all login threads
2788  //may start a settlement transaction concurrently.
2790 
2791  UINT64 iCurrentSettleTransactionNr = (++m_iCurrentSettleTransactionNr) % 50;
2792 
2794  if(dbInterface == NULL)
2795  {
2797  CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
2798  ret = E_NOT_CONNECTED;
2799  goto cleanup;
2800  }
2801 
2802 
2803  /* First part get unsettled CCs from the AI database */
2804  #ifdef DEBUG
2805  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
2806  #endif
2807 
2808  dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
2809  *nrOfSettledCCs = nrOfCCs;
2810  //no unsettled CCs found.
2811  if (allUnsettledCCs == NULL)
2812  {
2813  CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: thread %x looked for unsettled CCs, found no CCs to settle\n", iCurrentSettleTransactionNr, pthread_self());
2815  ret = E_SUCCESS;
2816  goto cleanup;
2817  }
2818 
2819 
2820  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x looked for unsettled CCs, found %u cost confirmations to settle\n", iCurrentSettleTransactionNr, pthread_self(), nrOfCCs);
2821 
2822  //connect to the PI
2823  biConnectionStatus = ms_pInstance->m_pPiInterface->initBIConnection();
2824  if(biConnectionStatus != E_SUCCESS)
2825  {
2828  {
2829  //transition to critical BI conn payment state
2830  MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
2831  }
2832  else
2833  {
2834  MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
2835  }
2836  ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
2837 
2839  dbInterface = NULL;
2841 
2842  CAMsg::printMsg(LOG_WARNING, "Settlement transaction: could not connect to BI. Try later...\n");
2843  //ret = E_SUCCESS;
2844  ret = E_NOT_CONNECTED;
2845  goto cleanup;
2846  }
2847  else
2848  {
2849  pErrMsgs = ms_pInstance->m_pPiInterface->settleAll(allUnsettledCCs, nrOfCCs, &settleException);
2851  }
2852 
2853  //workaround because usage of exceptions is not allowed!
2854  if(settleException != NULL)
2855  {
2857  dbInterface = NULL;
2858 
2860  CAMsg::printMsg(LOG_ERR, "Settlement transaction: BI reported settlement not successful: "
2861  "code: %i, %s \n", settleException->getErrorCode(),
2862  (settleException->getDescription() != NULL ?
2863  settleException->getDescription() : (UINT8*) "<no description given>") );
2864  ret = E_UNKNOWN;
2865  goto cleanup;
2866  }
2867 
2868  if(pErrMsgs == NULL)
2869  {
2870  //this must never happen because in any case where NULL is returned for pErrMsgs
2871  //'settleException' must not be NULL.
2873  dbInterface = NULL;
2874 
2876  CAMsg::printMsg(LOG_CRIT, "Settlement transaction: ErrorMessages are null.\n");
2877  ret = E_UNKNOWN;
2878  goto cleanup;
2879  }
2880  else
2881  {
2882  for(i = 0; i < nrOfCCs; i++)
2883  {
2884  nextEntry = __handleSettleResult(allUnsettledCCs[i], pErrMsgs[i], dbInterface, iCurrentSettleTransactionNr);
2885  if(nextEntry != NULL)
2886  {
2887  nextEntry->nextEntry = entry;
2888  entry = nextEntry;
2889  }
2890  }
2891  }
2892 
2893  //after settling: apply the corresponding account state changes reported from the PI.
2894  if (entry)
2895  {
2896  //wait numbers are used to obtain a synchronisation with FCFS assertion.
2897  //This additional synchronisation is necessary because before acquiring the login hashtable
2898  //locks the settlementMutex should be released. (Nested locking should be avoided).
2900  {
2901  //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
2902  //no one is waiting, we use this occasion to reset the wait numbers
2905  }
2906  else
2907  {
2908  //get global wait number and wait but release the DBConnection first.
2910  dbInterface = NULL;
2911  myWaitNr = ms_pInstance->m_settleWaitNr;
2913  while(myWaitNr != ms_pInstance->m_nextSettleNr)
2914  {
2915  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",
2916  iCurrentSettleTransactionNr, pthread_self(), (myWaitNr - ms_pInstance->m_nextSettleNr));
2918  }
2919 
2920  CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x may continue (1).\n", iCurrentSettleTransactionNr, pthread_self());
2922  }
2923 
2924  bool debugWarn = false;
2925  if (iCurrentSettleTransactionNr != (m_iCurrentSettleTransactionNr % 50))
2926  {
2927  debugWarn = true;
2928  // Write debug message in order to find deadlock...
2929  CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Apply changes to database. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
2930  }
2931 
2932  //first apply changes to the database ...
2933  __commitSettlementToDatabase(entry, dbInterface);
2935  dbInterface = NULL;
2936 
2937 
2938  if (debugWarn)
2939  {
2940  // Write debug message in order to find deadlock...
2941  CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Removing settlement mutex lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
2942  }
2943 
2945 
2946 
2947  if (debugWarn)
2948  {
2949  // Write debug message in order to find deadlock...
2950  CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Entering login hashtable. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
2951  }
2952 
2953  //... then to the login hashtable after releasing the global settlement lock.
2954  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
2955  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x with wait nr %llu alters hashtable.\n", iCurrentSettleTransactionNr, pthread_self(), myWaitNr);
2957  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
2958 
2959  if (debugWarn)
2960  {
2961  // Write debug message in order to find deadlock...
2962  CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: After commiting to login hashtable, before last lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
2963  }
2964 
2965  //indicate that the next thread may proceed with its settlement changes by incrementing the nextSettleNr.
2968 // TODO: seems to be a bug; if this "if" is set, some locks are never released
2969 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
2970  {
2971  //There are threads waiting for applying their settlement results.
2973  CAMsg::printMsg(LOG_INFO, "Thread %x waking up next Thread. %llu are still waiting.\n", pthread_self(),
2976  }
2977  }
2979 
2980 cleanup:
2981  if(dbInterface != NULL)
2982  {
2984  dbInterface = NULL;
2985  }
2986 
2987  if(allUnsettledCCs != NULL)
2988  {
2989  for(i = 0; i < nrOfCCs; i++)
2990  {
2991  delete allUnsettledCCs[i];
2992  allUnsettledCCs[i] = NULL;
2993  }
2994  delete [] allUnsettledCCs;
2995  allUnsettledCCs = NULL;
2996  }
2997 
2998  if(pErrMsgs != NULL)
2999  {
3000  for(i = 0; i < nrOfCCs; i++)
3001  {
3002  delete pErrMsgs[i];
3003  pErrMsgs[i] = NULL;
3004  }
3005  pErrMsgs = NULL;
3006  }
3007 
3008  while (entry != NULL)
3009  {
3010  nextEntry = entry->nextEntry;
3011  delete entry;
3012  entry = nextEntry;
3013  }
3014 
3015  delete settleException;
3016  settleException = NULL;
3017 
3018 
3019  CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu finished.\n", iCurrentSettleTransactionNr);
3020 
3021  return ret;
3022 }
3023 
3025  UINT64 a_iCurrentSettleTransactionNr)
3026 {
3027  bool bDeleteCC = false;
3028  UINT32 authFlags = 0;
3029  UINT32 authRemoveFlags = 0;
3030  UINT64 confirmedBytes = 0;
3031  UINT64 diffBytes = 0;
3032  UINT32 storedStatus = 0;
3033  SettleEntry *entry = NULL;
3034 
3035  dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
3036 
3037  // check returncode
3038  if(pErrMsg == NULL) //no returncode -> connection error
3039  {
3040  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
3041  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
3042  }
3043  else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK) //BI reported error
3044  {
3045  CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
3046  pErrMsg->getErrorCode(), pErrMsg->getDescription() );
3048  {
3049  authFlags |= AUTH_INVALID_ACCOUNT;
3050  //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
3051  bDeleteCC = true;
3052  }
3053  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
3054  {
3055  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3056  authFlags |= AUTH_ACCOUNT_EMPTY;
3057  UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
3058  if (msgConfirmedBytes)
3059  {
3060  confirmedBytes = *msgConfirmedBytes;
3061  if (confirmedBytes < pCC->getTransferredBytes())
3062  {
3063  diffBytes = pCC->getTransferredBytes() - confirmedBytes;
3064  }
3065  UINT8 tmp[32];
3066  print64(tmp, confirmedBytes);
3067  UINT8 tmp2[32];
3068  print64(tmp2, diffBytes);
3069  UINT8 tmp3[32];
3070  print64(tmp3, pCC->getTransferredBytes());
3071  CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
3072  }
3073  else
3074  {
3075  CAMsg::printMsg(LOG_INFO, "Settlement transaction: Account empty, no message object received. User will be kicked out.\n");
3076  }
3077 
3078  dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
3079  authFlags |= AUTH_SETTLED_ONCE;
3080  dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
3081  pCC->getTransferredBytes());
3082 //#ifdef DEBUG
3083  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
3084  pCC->getTransferredBytes(), pCC->getAccountNumber());
3085 //#endif
3086  }
3087  /*
3088  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
3089  {
3090  // this should never happen; the price certs in this CC do not fit to the ones of the cascade
3091  // bDeleteCC = true;
3092  }*/
3093  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
3094  {
3095  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
3096 
3097  //get attached CC from error message
3098  CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
3099  if (attachedCC)
3100  {
3101  authFlags |= AUTH_OUTDATED_CC;
3102  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
3103  //store it in DB
3104  if (dbInterface->storeCostConfirmation(*attachedCC,
3106  {
3107  authFlags |= AUTH_SETTLED_ONCE;
3108  if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
3109  attachedCC->getTransferredBytes()) != E_SUCCESS)
3110  {
3111  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
3112  "Maybe a new CC has been added meanwhile?\n");
3113  }
3114  }
3115  else
3116  {
3117  CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
3118  }
3119  // set the confirmed bytes to the value of the CC got from the PI
3120  confirmedBytes = attachedCC->getTransferredBytes();
3121  }
3122  else
3123  {
3124  CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
3125  }
3126  }
3127  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
3128  {
3129  authFlags |= AUTH_BLOCKED;
3130  bDeleteCC = true;
3131 
3132  dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
3133  }
3134 
3135  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
3136  {
3137  //authFlags |= AUTH_DATABASE;
3138  // the user is not responsible for this!
3139  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3140  }
3143  {
3144  // kick out the user and store the CC
3145  authFlags |= AUTH_UNKNOWN;
3146  }
3147  else
3148  {
3149  // an unknown error leads to user kickout
3150  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
3151  authFlags |= AUTH_UNKNOWN;
3152  bDeleteCC = true;
3153  }
3154 
3155  if (bDeleteCC)
3156  {
3157  //delete costconfirmation to avoid trying to settle an unusable CC again and again
3158  if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
3159  {
3160  CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
3161  }
3162  else
3163  {
3164  CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
3165  }
3166  }
3167  }
3168  else //settling was OK, so mark account as settled
3169  {
3170  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3171  authFlags |= AUTH_SETTLED_ONCE;
3172  if (dbInterface->markAsSettled(pCC->getAccountNumber(),
3174  pCC->getTransferredBytes()) != E_SUCCESS)
3175  {
3176  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
3177  }
3178 #ifdef DEBUG
3179  CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: CC OK for account %llu with %llu transferred bytes!\n",
3180  a_iCurrentSettleTransactionNr, pCC->getAccountNumber(), pCC->getTransferredBytes());
3181 #endif
3182  }
3183 
3184  if (authFlags || authRemoveFlags)
3185  {
3186  entry = new SettleEntry;
3187  entry->accountNumber = pCC->getAccountNumber();
3188  entry->authFlags = authFlags;
3189  entry->authRemoveFlags = authRemoveFlags;
3190  entry->confirmedBytes = confirmedBytes;
3191  entry->diffBytes = diffBytes;
3192  entry->storedStatus = storedStatus;
3193  }
3194  return entry;
3195 }
3196 
3199 {
3200  SettleEntry *entry = entryList, *nextEntry = NULL;
3201  while (entry != NULL && dbInterface != NULL)
3202  {
3203  if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
3204  {
3205  dbInterface->storePrepaidAmount(
3207  }
3208  else if (entry->diffBytes)
3209  {
3210  // user is currently not logged in; set correct prepaid bytes in DB
3211  SINT32 prepaidBytes =
3212  dbInterface->getPrepaidAmount(entry->accountNumber,
3214  if (prepaidBytes > 0)
3215  {
3216  if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
3217  {
3218  prepaidBytes = 0;
3219  }
3220  else
3221  {
3222  prepaidBytes -= entry->diffBytes;
3223  }
3224  dbInterface->storePrepaidAmount(
3225  entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
3226  }
3227  }
3228 
3230  entry->storedStatus != 0)
3231  {
3232  dbInterface->clearAccountStatus(entry->accountNumber);
3233  switch (entry->storedStatus)
3234  {
3236  {
3237  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
3238  entry->accountNumber);
3240  break;
3241  }
3243  {
3244  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
3245  entry->accountNumber);
3246  entry->authRemoveFlags |= AUTH_BLOCKED;
3247  break;
3248  }
3250  {
3251  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
3252  entry->accountNumber);
3254  break;
3255  }
3256  }
3257  }
3258  nextEntry = entry->nextEntry;
3259  entry = nextEntry;
3260  }
3261 }
3262 
3265 {
3266  SettleEntry *entry = entryList, *nextEntry = NULL;
3267  while (entry != NULL)
3268  {
3269  AccountLoginHashEntry* loginEntry =
3271  if (loginEntry)
3272  {
3273  // the user is currently logged in
3274  loginEntry->authFlags |= entry->authFlags;
3275  loginEntry->authRemoveFlags |= entry->authRemoveFlags;
3276  if (entry->confirmedBytes > 0 &&
3277  loginEntry->confirmedBytes < entry->confirmedBytes)
3278  {
3279  loginEntry->confirmedBytes = entry->confirmedBytes;
3280  }
3281  }
3282  nextEntry = entry->nextEntry;
3283  entry = nextEntry;
3284  }
3285 }
3286 
3287 /* Settlement transaction procedure as it is called by the SettleThread
3288  * NEVER INVOKE THIS METHOD IF YOU'RE HOLDING A LOCK ON m_currentAccountsHashtable !!
3289  * */
3291 {
3292  INIT_STACK;
3293  BEGIN_STACK("CAAccountingInstance::settlementTransaction");
3294 
3295  SINT32 ret = 0;
3296  CAXMLErrorMessage * pErrMsg = NULL;
3297  CAXMLCostConfirmation * pCC = NULL;
3298  //CAQueue q;
3299  CAXMLCostConfirmation **allUnsettledCCs = NULL;
3300  UINT32 /*size, qSize, */ nrOfCCs, i;
3301  SettleEntry *entry = NULL, *nextEntry = NULL;
3302 
3303  CAAccountingDBInterface *dbInterface = NULL;
3304 
3305  /* This should never happen */
3306  if(ms_pInstance == NULL)
3307  {
3308  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3309  return E_UNKNOWN;
3310  }
3311  /* This should never happen */
3312  if(ms_pInstance->m_pSettlementMutex == NULL)
3313  {
3314  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3315  return E_UNKNOWN;
3316  }
3317  //sleep(5);
3319  if(dbInterface == NULL)
3320  {
3321  CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
3322  //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
3323  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3324  return E_NOT_CONNECTED;
3325  }
3326  //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
3328  /* First part get unsettled CCs from the AI database */
3329  #ifdef DEBUG
3330  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
3331  #endif
3332 
3333  dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
3334  if (nrOfCCs <= 0)
3335  {
3336  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found no CCs to settle\n");
3337  if(dbInterface != NULL)
3338  {
3340  dbInterface = NULL;
3341  }
3343  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3344  return E_SUCCESS;
3345  }
3346  //qSize = q.getSize();
3347  //nrOfCCs = qSize / sizeof(pCC);
3348  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found %u cost confirmations to settle\n",nrOfCCs);
3349 
3350  SAVE_STACK("CAAccountingInstance::settlementTransaction", "After getting unsettled CCs");
3351  /* Second part: We found unsettled CCs. Now contact the Payment Instance to settle them */
3352 
3353  //while(!q.isEmpty())
3354  for(i = 0; i < nrOfCCs; i++)
3355  {
3356  // get the next CC from the queue
3357  /*size = sizeof(pCC);
3358  ret = q.get((UINT8*)(&pCC), &size);
3359  if(ret != E_SUCCESS)
3360  {
3361  CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not get next item from queue\n");
3362  q.clean();
3363  if(dbInterface != NULL)
3364  {
3365  CAAccountingDBInterface::releaseConnection(dbInterface);
3366  dbInterface = NULL;
3367  }
3368  ms_pInstance->m_pSettlementMutex->unlock();
3369  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3370  return ret;
3371  //break;
3372  }*/
3373  pCC = allUnsettledCCs[i];
3374  entry = NULL;
3375  nextEntry = NULL;
3376  if (!pCC)
3377  {
3378  CAMsg::printMsg(LOG_CRIT, "Settlement transaction: Cost confirmation is NULL!\n");
3379  continue;
3380  }
3381 
3382 #ifdef DEBUG
3383  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Connecting to payment instance...\n");
3384 #endif
3386  if(ret != E_SUCCESS)
3387  {
3390  {
3391  //transition to critical BI conn payment state
3392  MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
3393  }
3394  else
3395  {
3396  MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
3397  }
3398  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: could not connect to BI. Try later...\n");
3399  //q.clean();
3400  pErrMsg = NULL; // continue in order to tell AUTH_WAITING_FOR_FIRST_SETTLED_CC for all accounts
3401  ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
3402  }
3403  else
3404  {
3405  MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionSuccess);
3406 #ifdef DEBUG
3407  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: successfully connected to payment instance");
3408 #endif
3410  pErrMsg = ms_pInstance->m_pPiInterface->settle( *pCC );
3412  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settle done!\n");
3413  }
3414 
3415  bool bDeleteCC = false;
3416  UINT32 authFlags = 0;
3417  UINT32 authRemoveFlags = 0;
3418  UINT64 confirmedBytes = 0;
3419  UINT64 diffBytes = 0;
3420  UINT32 storedStatus = 0;
3421 
3422  dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
3423 
3424  // check returncode
3425  if(pErrMsg == NULL) //no returncode -> connection error
3426  {
3427  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
3428  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
3429  }
3430  else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK) //BI reported error
3431  {
3432  CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
3433  pErrMsg->getErrorCode(), pErrMsg->getDescription() );
3435  {
3436  authFlags |= AUTH_INVALID_ACCOUNT;
3437  //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
3438  bDeleteCC = true;
3439  }
3440  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
3441  {
3442  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3443  authFlags |= AUTH_ACCOUNT_EMPTY;
3444  UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
3445  if (msgConfirmedBytes)
3446  {
3447  confirmedBytes = *msgConfirmedBytes;
3448  if (confirmedBytes < pCC->getTransferredBytes())
3449  {
3450  diffBytes = pCC->getTransferredBytes() - confirmedBytes;
3451  }
3452  UINT8 tmp[32];
3453  print64(tmp, confirmedBytes);
3454  UINT8 tmp2[32];
3455  print64(tmp2, diffBytes);
3456  UINT8 tmp3[32];
3457  print64(tmp3, pCC->getTransferredBytes());
3458  CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
3459  }
3460  else
3461  {
3462  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Account empty, but no message object received! "
3463  "This may lead to too much prepaid bytes!\n");
3464  }
3465 
3466  dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
3467  authFlags |= AUTH_SETTLED_ONCE;
3468  dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
3469  pCC->getTransferredBytes());
3470 //#ifdef DEBUG
3471  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
3472  pCC->getTransferredBytes(), pCC->getAccountNumber());
3473 //#endif
3474  }
3475  /*
3476  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
3477  {
3478  // this should never happen; the price certs in this CC do not fit to the ones of the cascade
3479  // bDeleteCC = true;
3480  }*/
3481  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
3482  {
3483  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
3484 
3485  //get attached CC from error message
3486  CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
3487  if (attachedCC)
3488  {
3489  authFlags |= AUTH_OUTDATED_CC;
3490  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
3491  //store it in DB
3492  if (dbInterface->storeCostConfirmation(*attachedCC,
3494  {
3495  authFlags |= AUTH_SETTLED_ONCE;
3496  if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
3497  attachedCC->getTransferredBytes()) != E_SUCCESS)
3498  {
3499  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
3500  "Maybe a new CC has been added meanwhile?\n");
3501  }
3502  }
3503  else
3504  {
3505  CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
3506  }
3507  // set the confirmed bytes to the value of the CC got from the PI
3508  confirmedBytes = attachedCC->getTransferredBytes();
3509  }
3510  else
3511  {
3512  CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
3513  }
3514  }
3515  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
3516  {
3517  authFlags |= AUTH_BLOCKED;
3518  bDeleteCC = true;
3519 
3520  dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
3521  }
3522 
3523  else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
3524  {
3525  //authFlags |= AUTH_DATABASE;
3526  // the user is not responsible for this!
3527  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3528  }
3531  {
3532  // kick out the user and store the CC
3533  authFlags |= AUTH_UNKNOWN;
3534  }
3535  else
3536  {
3537  // an unknown error leads to user kickout
3538  CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
3539  authFlags |= AUTH_UNKNOWN;
3540  bDeleteCC = true;
3541  }
3542 
3543  if (bDeleteCC)
3544  {
3545  //delete costconfirmation to avoid trying to settle an unusable CC again and again
3546  if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
3547  {
3548  CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
3549  }
3550  else
3551  {
3552  CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
3553  }
3554  }
3555  }
3556  else //settling was OK, so mark account as settled
3557  {
3558  authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
3559  authFlags |= AUTH_SETTLED_ONCE;
3560  if (dbInterface->markAsSettled(pCC->getAccountNumber(),
3562  pCC->getTransferredBytes()) != E_SUCCESS)
3563  {
3564  CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
3565  }
3566  CAMsg::printMsg(LOG_INFO, "Settlement transaction: CC OK!\n");
3567  }
3568 
3569 
3570  if (authFlags || authRemoveFlags)
3571  {
3572  nextEntry = new SettleEntry;
3573  nextEntry->accountNumber = pCC->getAccountNumber();
3574  nextEntry->authFlags = authFlags;
3575  nextEntry->authRemoveFlags = authRemoveFlags;
3576  nextEntry->confirmedBytes = confirmedBytes;
3577  nextEntry->diffBytes = diffBytes;
3578  nextEntry->nextEntry = entry;
3579  nextEntry->storedStatus = storedStatus;
3580  entry = nextEntry;
3581  }
3582 
3583  /*if (pCC != NULL)
3584  {
3585  delete pCC;
3586  pCC = NULL;
3587  }*/
3588  if (pErrMsg != NULL)
3589  {
3590  delete pErrMsg;
3591  pErrMsg = NULL;
3592  }
3593  }
3594 
3595  if(allUnsettledCCs != NULL)
3596  {
3597  for(i = 0; i < nrOfCCs; i++)
3598  {
3599  delete allUnsettledCCs[i];
3600  allUnsettledCCs[i] = NULL;
3601  }
3602  delete [] allUnsettledCCs;
3603  allUnsettledCCs = NULL;
3604  }
3605 
3606  SAVE_STACK("CAAccountingInstance::settlementTransaction", "After settling unsettled CCs with BI");
3607 
3608  SettleEntry *first = entry;
3609  UINT64 myWaitNr = 0;
3610  if (entry)
3611  {
3612  //wait numbers are used to obtain a synchronisation with FCFS assertion.
3613  //This additional synchronisation is necessary because before acquiring the login hashtable
3614  //locks the settlementMutex should be released. (Nested locking should be avoided).
3616  {
3617  //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
3618  //no one is waiting, we use this occasion to reset the wait numbers
3621  }
3622  else
3623  {
3624  SAVE_STACK("CAAccountingInstance::settlementTransaction", "wait for altering hashtable");
3625  //get global wait number and wait but release the DBConnection first.
3627  dbInterface = NULL;
3628  myWaitNr = ms_pInstance->m_settleWaitNr;
3630  while(myWaitNr != ms_pInstance->m_nextSettleNr)
3631  {
3632  CAMsg::printMsg(LOG_INFO, "Thread %x must wait to alter login table after settling (2): %llu before him in the queue\n", pthread_self(),
3633  (myWaitNr - ms_pInstance->m_nextSettleNr));
3635  }
3636  CAMsg::printMsg(LOG_INFO, "Thread %x may continue (2).\n", pthread_self());
3638  }
3639  SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering DB entries");
3640  while (entry != NULL && dbInterface != NULL)
3641  {
3642  if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
3643  {
3644  dbInterface->storePrepaidAmount(
3646  }
3647  else if (entry->diffBytes)
3648  {
3649  // user is currently not logged in; set correct prepaid bytes in DB
3650  SINT32 prepaidBytes =
3651  dbInterface->getPrepaidAmount(entry->accountNumber,
3653  if (prepaidBytes > 0)
3654  {
3655  if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
3656  {
3657  prepaidBytes = 0;
3658  }
3659  else
3660  {
3661  prepaidBytes -= entry->diffBytes;
3662  }
3663  dbInterface->storePrepaidAmount(
3664  entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
3665  }
3666  }
3667 
3669  entry->storedStatus != 0)
3670  {
3671  dbInterface->clearAccountStatus(entry->accountNumber);
3672  switch (entry->storedStatus)
3673  {
3675  {
3676  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
3677  entry->accountNumber);
3679  break;
3680  }
3682  {
3683  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
3684  entry->accountNumber);
3685  entry->authRemoveFlags |= AUTH_BLOCKED;
3686  break;
3687  }
3689  {
3690  CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
3691  entry->accountNumber);
3693  break;
3694  }
3695  }
3696  }
3697 
3698  nextEntry = entry->nextEntry;
3699  entry = nextEntry;
3700  }
3701  }
3703  dbInterface = NULL;
3705 
3706  if(first != NULL)
3707  {
3708  SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering hashtable");
3709 #ifdef DEBUG
3710  CAMsg::printMsg(LOG_DEBUG, "Settlement thread with wait nr %llu alters hashtable.\n", myWaitNr);
3711 #endif
3712  entry = first;
3713  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
3714  while (entry != NULL)
3715  {
3716  AccountLoginHashEntry* loginEntry =
3718  if (loginEntry)
3719  {
3720  // the user is currently logged in
3721  loginEntry->authFlags |= entry->authFlags;
3722  loginEntry->authRemoveFlags |= entry->authRemoveFlags;
3723  if (entry->confirmedBytes > 0 &&
3724  loginEntry->confirmedBytes < entry->confirmedBytes)
3725  {
3726  loginEntry->confirmedBytes = entry->confirmedBytes;
3727  }
3728  }
3729  nextEntry = entry->nextEntry;
3730  delete entry;
3731  entry = nextEntry;
3732  }
3733  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
3734 
3737 // TODO: seems to be a bug; if this "if" is set, some locks are never released
3738 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
3739  {
3740  SAVE_STACK("CAAccountingInstance::settlementTransaction", "waking up waiting threads for altering hashtable");
3741  //There are threads waiting for applying their settlement results.
3743  CAMsg::printMsg(LOG_INFO, "Thread %x Waking up next Thread %llu are waiting.\n", pthread_self(),
3746  }
3748  }
3749 
3750  /*if(dbInterface != NULL)
3751  {
3752  CAAccountingDBInterface::releaseConnection(dbInterface);
3753  dbInterface = NULL;
3754  }*/
3755  FINISH_STACK("CAAccountingInstance::settlementTransaction");
3756  return E_SUCCESS;
3757 }
3758 
3764 {
3765  bool success = false;
3766  loginEntry->ownerLock->lock();
3767  success = !loginEntry->loginOngoing;
3768  if(success)
3769  {
3770  //CAMsg::printMsg(LOG_DEBUG,"login free, owner %x \n", loginEntry->ownerRef);
3771  loginEntry->ownerRef = ownerRef;
3772  loginEntry->loginOngoing = true;
3773  }
3774  /*else
3775  {
3776  CAMsg::printMsg(LOG_DEBUG,"login ongoing, owner %x \n", loginEntry->ownerRef);
3777  }*/
3778  loginEntry->ownerLock->unlock();
3779  return success;
3780 }
3781 
3787 {
3788  if(ownerRef == NULL || ownerRef->pAccountingInfo == NULL)
3789  {
3790  return 0;
3791  }
3792  UINT64 accountNumber = ownerRef->pAccountingInfo->accountNumber;
3793  ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
3794  AccountLoginHashEntry *loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
3795  if (loginEntry != NULL)
3796  {
3797  resetLoginOngoing(loginEntry, ownerRef);
3798  }
3799  ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
3800  return accountNumber;
3801 }
3802 
3806 bool resetLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
3807 {
3808  bool success = false;
3809  loginEntry->ownerLock->lock();
3810  success = testLoginEntryOwner_internal(loginEntry, ownerRef);
3811  if(success)
3812  {
3813  loginEntry->loginOngoing = false;
3814  //CAMsg::printMsg(LOG_DEBUG,"resetted for %x.\n", loginEntry->ownerRef);
3815  }
3816  /*else
3817  {
3818  CAMsg::printMsg(LOG_DEBUG,"not resetted for %x.\n", loginEntry->ownerRef);
3819  }*/
3820  loginEntry->ownerLock->unlock();
3821  return success;
3822 }
3823 
3828 {
3829  bool ret;
3830  loginEntry->ownerLock->lock();
3831  ret = testLoginEntryOwner_internal(loginEntry, ownerRef);
3832  loginEntry->ownerLock->unlock();
3833  return ret;
3834 }
3835 
3839 bool isLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
3840 {
3841  bool ret;
3842  loginEntry->ownerLock->lock();
3843  ret = loginEntry->loginOngoing;
3844  loginEntry->ownerLock->unlock();
3845  return ret;
3846 }
3847 
3848 inline bool testLoginEntryOwner_internal(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
3849 {
3850  return (loginEntry->ownerRef == ownerRef);
3851 }
3852 #endif /* ifdef PAYMENT */
bool testAndSetLoginOwner(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
if the current login entry isn't locked by a login thread the calling login-thread obtains ownership
bool testLoginEntryOwner(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
tests whether the corresponding ownerEntry owns this loginEntry.
bool isLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
test whether this entry is currently resrved by an ongoing login process.
bool testLoginEntryOwner_internal(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
bool resetLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
indicates that the ongoing login process for this entry is finished but doesn't reset ownership.
#define PREPAID_PROTO_CLIENT_VERSION
#define CRITICAL_SUBSEQUENT_BI_CONN_ERRORS
#define CRITICAL_SETTLE_FLAGS
#define HARD_LIMIT_TIMEOUT
#define CLIENT_VERSION_STR_LEN
#define MONITORING_FIRE_PAY_EVENT(e_type)
#define INIT_STACK
Definition: CAThread.hpp:48
#define BEGIN_STACK(methodName)
Definition: CAThread.hpp:49
#define FINISH_STACK(methodName)
Definition: CAThread.hpp:50
#define SAVE_STACK(methodName, methodPosition)
Definition: CAThread.hpp:51
SINT32 setDOMElementAttribute(DOMNode *pElem, const char *attrName, const char *value)
Definition: CAUtil.cpp:831
SINT32 getcurrentTimeMillis(UINT64 &u64Time)
Gets the current Systemtime in milli seconds.
Definition: CAUtil.cpp:252
SINT32 getDOMElementValue(const DOMNode *const pElem, UINT8 *value, UINT32 *valuelen)
Returns the content of the text node(s) under elem as null-terminated C String.
Definition: CAUtil.cpp:746
SINT32 setDOMElementValue(DOMElement *pElem, SINT32 value)
Definition: CAUtil.cpp:939
UINT32 strtrim(UINT8 *s)
Removes leading and ending whitespaces (chars<=32) from a zero terminated string.
Definition: CAUtil.cpp:49
DOMNodeList * getElementsByTagName(DOMElement *pElem, const char *const name)
Definition: CAUtil.cpp:1711
SINT32 getRandom(UINT32 *val)
Gets 32 random bits.
Definition: CAUtil.cpp:346
XERCES_CPP_NAMESPACE::DOMDocument * createDOMDocument()
Parses a timestamp in JDBC timestamp escape format (as it comes from the BI) and outputs the value in...
Definition: CAUtil.cpp:1568
DOMElement * createDOMElement(XERCES_CPP_NAMESPACE::DOMDocument *pOwnerDoc, const char *const name)
Creates a new DOMElement with the given name which belongs to the DOMDocument owernDoc.
Definition: CAUtil.cpp:814
SINT32 getDOMChildByName(const DOMNode *pNode, const char *const name, DOMElement *&child, bool deep)
Definition: CAUtil.cpp:458
SINT32 getcurrentTime(timespec &t)
Gets the current Systemtime in milli seconds.
Definition: CAUtil.cpp:227
void print64(UINT8 *buff, UINT64 num)
Definition: CAUtil.hpp:482
#define NUM_LOGIN_WORKER_TRHEADS
Definition: StdAfx.h:202
#define THREAD_RETURN
Definition: StdAfx.h:540
#define THREAD_RETURN_SUCCESS
Definition: StdAfx.h:542
#define MAX_LOGIN_QUEUE
Definition: StdAfx.h:203
signed int SINT32
Definition: basetypedefs.h:132
unsigned char UINT8
Definition: basetypedefs.h:135
unsigned int UINT32
Definition: basetypedefs.h:131
SINT32 sendXMLMessage(const XERCES_CPP_NAMESPACE::DOMDocument *pDocMsg) const
Call to send a XML message via this control channel.
SINT32 toXmlDocument(XERCES_CPP_NAMESPACE::DOMDocument *&pDoc)
returns a pointer to the tagname of this XML structure's top level element.
This class encapsulates the connection to the JPI.
SINT32 terminateBIConnection()
Terminate HTTP(s) connection to the BI (JPI)
SINT32 initBIConnection()
Establishes HTTP(s) connection to the BI (JPI)
CAXMLErrorMessage ** settleAll(CAXMLCostConfirmation **CCs, UINT32 nrOfCCs, CAXMLErrorMessage **settleException)
SINT32 setPIServerConfiguration(CAXMLBI *pPiServerConfig)
CAXMLErrorMessage * settle(CAXMLCostConfirmation &cc)
Send a cost confirmation to the JPI.
SINT32 storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8 *cascadeId)
static CAAccountingDBInterface * getConnection()
SINT32 storeCostConfirmation(CAXMLCostConfirmation &cc, UINT8 *ccCascade)
Creates the tables we need in the DB.
SINT32 clearAccountStatus(UINT64 a_accountNumber)
static SINT32 releaseConnection(CAAccountingDBInterface *dbIf)
SINT32 getCostConfirmation(UINT64 accountNumber, UINT8 *cascadeId, CAXMLCostConfirmation **pCC, bool &a_bSettled)
SINT32 getAccountStatus(UINT64 a_accountNumber, UINT32 &a_statusCode)
SINT32 deleteCC(UINT64 accountNumber, UINT8 *cascadeId)
if the BI reports an error while trying to settle a CC, this will be called to delete it from the dat...
SINT32 getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8 *cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
Fills the CAQueue with all non-settled cost confirmations.
SINT32 storeAccountStatus(UINT64 a_accountNumber, UINT32 a_statusCode)
SINT32 markAsSettled(UINT64 accountNumber, UINT8 *cascadeId, UINT64 a_transferredBytes)
Marks this account as settled.
SINT32 getPrepaidAmount(UINT64 accountNumber, UINT8 *cascadeId, bool a_bDelete)
This is the AI (accounting instance or abrechnungsinstanz in german) class.
static const SINT32 HANDLE_PACKET_CONNECTION_OK
static SettleEntry * __handleSettleResult(CAXMLCostConfirmation *pCC, CAXMLErrorMessage *pErrMsg, CAAccountingDBInterface *dbInterface, UINT64 a_iSettlementTransactionNr)
static const UINT32 MAX_SETTLED_CCS
UINT8 * m_currentCascade
current cascade (identified by the concatenated hash values of the price certificates)
static SINT32 getPrepaidBytes(tAiAccountingInfo *pAccInfos)
static SINT32 returnPrepareKickout(tAiAccountingInfo *pAccInfo, CAXMLErrorMessage *a_error)
UINT32 handleCostConfirmation(tAiAccountingInfo *pAccInfo, DOMElement *root)
Handles a cost confirmation sent by a jap.
static SINT32 sendAILoginConfirmation(tAiAccountingInfo *pAccInfo, const UINT32 code, UINT8 *message)
CAAccountingInstance(CAFirstMix *callingMix)
private Constructor
static SINT32 handleJapPacket_internal(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
Called by FirstMix for each incoming JAP packet.
static const SINT32 HANDLE_PACKET_CLOSE_CONNECTION
~CAAccountingInstance()
private destructor
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 ...
static SINT32 returnKickout(tAiAccountingInfo *pAccInfo)
When receiving this message, the Mix should kick the user out immediately.
static void setPrepaidBytesToZero_internal(tAiAccountingInfo *pAccInfo)
CAAccountingSettleThread * m_pSettleThread
Signature verifying instance for BI signatures.
CAMutex * m_pMutex
this is for synchronizing the write access to the HashEntries
static void __commitSettlementToLoginTable(SettleEntry *entryList)
only for internal use during the settleTransaction because no login table locks are acquired
static const SINT32 HANDLE_PACKET_HOLD_CONNECTION
static const UINT32 MAX_TOLERATED_MULTIPLE_LOGINS
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.
volatile UINT32 m_seqBIConnErrors
static SINT32 handleJapPacket(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
This should be called by the FirstMix for every incoming Jap packet.
static void setPrepaidBytesToZero(tAiAccountingInfo *pAccInfo)
static SINT32 loginProcessStatus(fmHashTableEntry *pHashEntry)
UINT32 handleCostConfirmation_internal(tAiAccountingInfo *pAccInfo, DOMElement *root)
Handles a cost confirmation sent by a jap.
CAThreadPool * m_aiThreadPool
reads messages from the queue and processes them
UINT32 handleChallengeResponse(tAiAccountingInfo *pAccInfo, DOMElement *root)
Checks the response of the challenge-response auth.
static SINT32 settlementTransaction()
CAAccountingBIInterface * m_pPiInterface
the interface to the database
static SINT32 initTableEntry(fmHashTableEntry *pHashEntry)
This must be called whenever a JAP is connecting to init our per-user data structures.
static SINT32 newSettlementTransaction()
static CAAccountingInstance * ms_pInstance
Singleton: This is the reference to the only instance of this class.
static void __commitSettlementToDatabase(SettleEntry *entryList, CAAccountingDBInterface *dbInterface)
only for internal use during the settleTransaction because the global settlement lock is not acquired
UINT8 ** m_allHashes
The hash values of the Mixes ordered beginning with the AI Mix.
UINT8 * m_AiName
the name of this accounting instance
static const UINT64 PACKETS_BEFORE_NEXT_CHECK
static volatile UINT64 m_iCurrentSettleTransactionNr
UINT32 handleChallengeResponse_internal(tAiAccountingInfo *pAccInfo, DOMElement *root)
Handles the response to our challenge.
static UINT64 unlockLogin(fmHashTableEntry *ownerRef)
release login (particularly for use in error case) this function is thread-safe.
SINT32 prepareCCRequest(CAMix *callingMix, UINT8 *a_AiName)
creating the xml of a new CC is really the responsability of the CAXMLCostConfirmation class knowledg...
UINT32 handleAccountCertificate_internal(tAiAccountingInfo *pAccInfo, DOMElement *root)
Handles an account certificate of a newly connected Jap.
static SINT32 sendCCRequest(tAiAccountingInfo *pAccInfo)
UINT32 handleAccountCertificate(tAiAccountingInfo *pAccInfo, DOMElement *root)
Handles an account certificate of a newly connected Jap.
static UINT32 getAuthFlags(fmHashTableEntry *pHashEntry)
static const SINT32 HANDLE_PACKET_CONNECTION_UNCHECKED
Hashtable * m_currentAccountsHashtable
Stores the account number of all users currently logged in.
static SINT32 __newSettlementTransaction(UINT32 *nrOfSettledCCs)
bool cascadeMatchesCC(CAXMLCostConfirmation *pCC)
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 m...
static SINT32 cleanupTableEntry(fmHashTableEntry *pHashEntry)
This should always be called when closing a JAP connection to cleanup the data structures.
static SINT32 makeCCRequest(const UINT64 accountNumber, const UINT64 transferredBytes, XERCES_CPP_NAMESPACE::DOMDocument *&doc)
static SINT32 sendInitialCCRequest(tAiAccountingInfo *pAccInfo, CAXMLCostConfirmation *pCC, SINT32 prepaidBytes)
static const SINT32 HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION
CAConditionVariable * m_pSettlementMutex
static XERCES_CPP_NAMESPACE::DOMDocument * m_preparedCCRequest
static void processJapMessageLoginHelper(fmHashTableEntry *pHashEntry, UINT32 handlerReturnvalue, bool finishLogin)
static SINT32 finishLoginProcess(fmHashTableEntry *pHashEntry)
this method is for the corresponding CAFirstMix login thread to verify the result of the settlement.
A thread that settles CCs with the BI.
static SINT32 encode(const UINT8 *in, UINT32 len, UINT8 *out, UINT32 *outlen)
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff...
Definition: CABase64.cpp:102
static SINT32 decode(const UINT8 *in, UINT32 len, UINT8 *out, UINT32 *outlen)
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff...
Definition: CABase64.cpp:41
SINT32 getAiID(UINT8 *id, UINT32 len)
UINT32 getPrepaidInterval()
UINT32 getPaymentHardLimit()
UINT32 getPaymentSoftLimit()
SINT32 signal()
Signals this object.
SINT32 wait()
Waits for a signal or for a timeout.
CAMutex * getLoginMutex()
Definition: CAFirstMix.hpp:325
bool forceKickout(fmHashTableEntry *pHashTableEntry, const XERCES_CPP_NAMESPACE::DOMDocument *pErrDoc=NULL)
static CACmdLnOptions * getOptions()
Definition: CAMix.hpp:49
SINT32 getMixCascadeInfo(XERCES_CPP_NAMESPACE::DOMDocument *&docMixCascadeInfo)
Returns the Mix-Cascade info which should be send to the InfoService.
Definition: CAMix.hpp:96
static SINT32 printMsg(UINT32 typ, const char *format,...)
Writes a given message to the log.
Definition: CAMsg.cpp:251
static SINT32 verifyXML(const UINT8 *const in, UINT32 inlen, CACertificate *a_cert)
SINT32 unlock()
Definition: CAMutex.hpp:52
SINT32 lock()
Definition: CAMutex.hpp:41
SINT32 verifyDER(UINT8 *in, UINT32 inlen, const UINT8 *dsaSig, const UINT32 sigLen)
Verifies an ASN.1 DER encoded SHA1-DSA signature.
SINT32 setVerifyKey(CACertificate *pCert)
Set the key for signature testing to the one include in pCert.
SINT32 verifyXML(DOMNode *node, CACertStore *pTrustedCerts=NULL)
Verifies a XML Signature under node root.
This class bla bla.
This class encapsulates an error or success message.
static const UINT32 ERR_BAD_REQUEST
static const UINT32 ERR_WRONG_DATA
static const UINT32 ERR_BAD_SIGNATURE
static const UINT32 ERR_ACCOUNT_EMPTY
static const UINT32 ERR_NO_ERROR_GIVEN
static const UINT32 ERR_WRONG_FORMAT
static const UINT32 ERR_OUTDATED_CC
static const UINT32 ERR_MULTIPLE_LOGIN
static const UINT32 ERR_DATABASE_ERROR
static const UINT32 ERR_NO_CONFIRMATION
static const UINT32 ERR_OK
static const UINT32 ERR_NO_RECORD_FOUND
static const UINT32 ERR_NO_BALANCE
static const UINT32 ERR_KEY_NOT_FOUND
static const UINT32 ERR_BLOCKED
static const UINT32 ERR_INTERNAL_SERVER_ERROR
static const UINT32 ERR_SUCCESS_BUT_WITH_ERRORS
static SINT32 makeCanonical(const DOMNode *node, UINT8 *buff, UINT32 *size)
Dumps the node and all childs in a 'cannonical form' into buff.
Definition: DOM_Output.hpp:212
static SINT32 dumpToMem(const DOMNode *node, UINT8 *buff, UINT32 *size)
Dumps the node and all childs into buff.
Definition: DOM_Output.hpp:161
const SINT32 E_SUCCESS
Definition: errorcodes.hpp:2
#define E_NOT_CONNECTED
Definition: errorcodes.hpp:22
#define E_UNKNOWN
Definition: errorcodes.hpp:3
void cleanup()
do necessary cleanups of libraries etc.
Definition: proxytest.cpp:151
UINT64 confirmedBytes
UINT32 count
bool loginOngoing
UINT32 authRemoveFlags
UINT64 userID
UINT64 accountNumber
struct t_fmhashtableentry * ownerRef
UINT32 authFlags
CAMutex * ownerLock
void(CAAccountingInstance::* handleFunc)(tAiAccountingInfo *, DOMElement *)
XERCES_CPP_NAMESPACE::DOMDocument * pDomDoc
SettleEntry * nextEntry
UINT32 authFlags
UINT32 authRemoveFlags
UINT64 accountNumber
UINT64 confirmedBytes
SINT32 storedStatus
UINT64 diffBytes
Structure that holds all per-user payment information Included in CAFirstMixChannelList (struct fmHas...
Definition: typedefs.hpp:301
CAMutex * mutex
Definition: typedefs.hpp:302
CASignature * pPublicKey
the signature verifying instance for this user
Definition: typedefs.hpp:308
UINT64 bytesToConfirm
The bytes the user could confirm in the last CC sent to him.
Definition: typedefs.hpp:320
SINT32 lastHardLimitSeconds
timestamp when last HardLimit was reached
Definition: typedefs.hpp:336
UINT8 * pstrBIID
ID of payment instance belonging to this account.
Definition: typedefs.hpp:342
struct t_fmhashtableentry * ownerRef
Definition: typedefs.hpp:328
SINT32 challengeSentSeconds
timestamp when last PayRequest was sent
Definition: typedefs.hpp:339
SINT32 authTimeoutStartSeconds
Definition: typedefs.hpp:345
UINT8 * pChallenge
we store the challenge here to verify the response later
Definition: typedefs.hpp:305
UINT32 authFlags
Flags, see above AUTH_*.
Definition: typedefs.hpp:333
UINT64 sessionPackets
The number of packets transfered.
Definition: typedefs.hpp:311
UINT64 accountNumber
the user's account number
Definition: typedefs.hpp:323
UINT64 userID
The same value as in fmHashTableEntry.
Definition: typedefs.hpp:326
UINT64 confirmedBytes
the number of bytes that was confirmed by the account user
Definition: typedefs.hpp:317
UINT8 * clientVersion
Definition: typedefs.hpp:351
CAAccountingControlChannel * pControlChannel
a pointer to the user-specific control channel object
Definition: typedefs.hpp:330
UINT64 transferredBytes
the number of bytes that was transferred (as counted by the AI) Elmar: since last CC,...
Definition: typedefs.hpp:314
CAConditionVariable * cleanupNotifier
tAiAccountingInfo * pAccountingInfo
#define AUTH_HARD_LIMIT_REACHED
Definition: typedefs.hpp:253
struct t_accountinginfo tAiAccountingInfo
Definition: typedefs.hpp:353
#define MIXPACKET_SIZE
Definition: typedefs.hpp:40
#define AUTH_MULTIPLE_LOGIN
Definition: typedefs.hpp:275
#define AUTH_ACCOUNT_EMPTY
the account is empty
Definition: typedefs.hpp:262
#define AUTH_LOGIN_NOT_FINISHED
Definition: typedefs.hpp:288
#define AUTH_UNKNOWN
Definition: typedefs.hpp:277
#define AUTH_FAKE
the user tried to fake something
Definition: typedefs.hpp:256
#define AUTH_CHALLENGE_SENT
we have sent a challenge and not yet received the response
Definition: typedefs.hpp:259
#define AUTH_INVALID_ACCOUNT
Account does not exist.
Definition: typedefs.hpp:270
#define AUTH_LOGIN_FAILED
Definition: typedefs.hpp:289
#define AUTH_OUTDATED_CC
Definition: typedefs.hpp:267
#define AUTH_WAITING_FOR_FIRST_SETTLED_CC
First CC from client has not been settled yet.
Definition: typedefs.hpp:239
#define AUTH_SENT_ACCOUNT_REQUEST
we have sent one request for an accountcertificate
Definition: typedefs.hpp:251
#define AUTH_FATAL_ERROR
a fatal error occured earlier
Definition: typedefs.hpp:265
#define AUTH_ACCOUNT_OK
format and signature of all received certificates was OK
Definition: typedefs.hpp:236
#define AUTH_GOT_ACCOUNTCERT
user has sent an account certificate
Definition: typedefs.hpp:233
#define AUTH_BLOCKED
Account has been blocked temporarly.
Definition: typedefs.hpp:248
#define AUTH_TIMEOUT_STARTED
Definition: typedefs.hpp:273
#define AUTH_DELETE_ENTRY
Definition: typedefs.hpp:286
UINT16 len
Definition: typedefs.hpp:0
#define AUTH_SENT_CC_REQUEST
we have sent one or two CC requests
Definition: typedefs.hpp:242
#define AUTH_LOGIN_SKIP_SETTLEMENT
Definition: typedefs.hpp:290
#define AUTH_DATABASE
A database error occured (internal or in the BI)
Definition: typedefs.hpp:245
#define AUTH_SETTLED_ONCE
Definition: typedefs.hpp:280