Mixe for Privacy and Anonymity in the Internet
CAAccountingDBInterface.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2000, The JAP-Team
3 All rights reserved.
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6 
7  - Redistributions of source code must retain the above copyright notice,
8  this list of conditions and the following disclaimer.
9 
10  - Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation and/or
12  other materials provided with the distribution.
13 
14  - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
15  may be used to endorse or promote products derived from this software without specific
16  prior written permission.
17 
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
20 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
27 */
28 #include "StdAfx.h"
29 #ifdef PAYMENT
31 #include "CACmdLnOptions.hpp"
32 #include "CAXMLErrorMessage.hpp"
33 #include "CAMsg.hpp"
34 #include "CAStatusManager.hpp"
35 #include "CALibProxytest.hpp"
36 
41 
46  {
47  m_bConnected = false;
48  m_dbConn=NULL;/* The owner of the connection */
49  m_owner = 0;
50  /* indicates whether this connection is not owned by a thread.
51  * (There is no reliable value of m_owner to indicate this).
52  */
53  m_free = true;
54  /* to ensure atomic access to m_owner and m_free */
56  }
57 
58 
63  {
65  delete m_pConnectionMutex;
66  m_pConnectionMutex = NULL;
67  }
68 
69 
79  {
80  if(m_bConnected)
81  {
82  return E_UNKNOWN;
83  }
84 
85  // Get database connection info from configfile and/or commandline
86  UINT8 host[255];
87  if(CALibProxytest::getOptions()->getDatabaseHost(host, 255) != E_SUCCESS)
88  {
89  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Host!\n");
90  return E_UNKNOWN;
91  }
93  UINT8 dbName[255];
94  if(CALibProxytest::getOptions()->getDatabaseName(dbName, 255) != E_SUCCESS)
95  {
96  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Name!\n");
97  return E_UNKNOWN;
98  }
99  UINT8 userName[255];
100  if(CALibProxytest::getOptions()->getDatabaseUsername(userName, 255) != E_SUCCESS)
101  {
102  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Username!\n");
103  return E_UNKNOWN;
104  }
105  UINT8 password[255];
106  if(CALibProxytest::getOptions()->getDatabasePassword(password, 255) != E_SUCCESS)
107  {
108  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Error, no Database Password!\n");
109  return E_UNKNOWN;
110  }
111 
112 
113  char port[20];
114  sprintf(port, "%i", tcp_port);
115  m_dbConn = PQsetdbLogin(
116  (char*)host, port, "", "",
117  (char*)dbName, (char*)userName, (char*)password
118  );
119  if(m_dbConn==NULL||PQstatus(m_dbConn) == CONNECTION_BAD)
120  {
122  LOG_ERR, "CAAccountingDBInterface: Could not connect to Database. Reason: %s\n",
123  PQerrorMessage(m_dbConn)
124  );
125  PQfinish(m_dbConn);
126  m_dbConn = NULL;
127  m_bConnected = false;
128  return E_NOT_CONNECTED;
129  }
130  m_bConnected = true;
131  return E_SUCCESS;
132  }
133 
135 {
136  if (!m_bConnected)
137  {
138  return false;
139  }
140 
141  if (PQstatus(m_dbConn) != CONNECTION_OK)
142  {
143  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Connection to database lost! Reason: %s\n",
144  PQerrorMessage(m_dbConn));
145  PQreset(m_dbConn);
146 
147  if (PQstatus(m_dbConn) != CONNECTION_OK)
148  {
149  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not reset database connection! Reason: %s\n",
150  PQerrorMessage(m_dbConn));
152  }
153  else
154  {
155  CAMsg::printMsg(LOG_INFO, "CAAccountingDBInterface: Database connection has been reset successfully!");
156  }
157  }
158  return m_bConnected;
159 }
160 
162 {
163  return m_bConnected;
164 }
165 
171 {
172  if(m_bConnected)
173  {
174  PQfinish(m_dbConn);
175  }
176  m_dbConn=NULL;
177  m_bConnected = false;
178  return E_SUCCESS;
179 }
180 
181 
183 {
184  bool isFree = false;
185  thread_id_t owner = 0;
187  owner = m_owner;
188  isFree = m_free;
190 
191  return ( (owner==CAThread::getSelfID()) && !isFree);
192 }
193 
194 /* Thread safe DB Query method */
195 SINT32 CAAccountingDBInterface::getCostConfirmation(UINT64 accountNumber, UINT8* cascadeId, CAXMLCostConfirmation **pCC, bool& a_bSettled)
196 {
197  if(checkOwner())
198  {
199  return __getCostConfirmation(accountNumber, cascadeId, pCC, a_bSettled);
200  }
201  else
202  {
203  return E_UNKNOWN;
204  }
205 }
218 SINT32 CAAccountingDBInterface::__getCostConfirmation(UINT64 accountNumber, UINT8* cascadeId, CAXMLCostConfirmation **pCC, bool& a_bSettled)
219  {
220  if(!checkConnectionStatus())
221  {
222  /* We assume, that the DB Connection was obtained by CAAccountingDBInterface::getConnnection
223  * which shall return an established DBConnection. Therefore this is an error event
224  */
225  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
226  return E_NOT_CONNECTED;
227  }
228 
229  const char* queryF = "SELECT XMLCC, SETTLED FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
230  UINT8* query;
231  UINT8* xmlCC;
232  PGresult* result;
233  UINT8 tmp[32];
234  print64(tmp,accountNumber);
235 
236  query = new UINT8[strlen(queryF) + 32 + strlen((char*)cascadeId)];
237  sprintf( (char *)query, queryF, tmp, cascadeId);
238  #ifdef DEBUG
239  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: executing query %s\n", query);
240  #endif
241 
242  result = monitored_PQexec(m_dbConn, (char *)query);
243 
244  delete[] query;
245  query = NULL;
246  if(PQresultStatus(result)!=PGRES_TUPLES_OK)
247  {
248  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not read XMLCC. Reason: %s\n",
249  PQresultErrorMessage(result));
250  PQclear(result);
251  return E_UNKNOWN;
252  }
253 
254  if(PQntuples(result)!=1)
255  {
256  #ifdef DEBUG
257  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: XMLCC not found.\n");
258  #endif
259  PQclear(result);
260  return E_NOT_FOUND;
261  }
262 
263  xmlCC = (UINT8*) PQgetvalue(result, 0, 0);
264  if (atoi(PQgetvalue(result, 0, 1)) == 0)
265  {
266  a_bSettled = false;
267  }
268  else
269  {
270  a_bSettled = true;
271  }
272 
273  *pCC = CAXMLCostConfirmation::getInstance(xmlCC,strlen((char*)xmlCC));
274  PQclear(result);
275 
276  if(*pCC==NULL)
277  {
278  return E_UNKNOWN;
279  }
280  return E_SUCCESS;
281  }
282 
284 {
285  if(checkOwner())
286  {
287  return __checkCountAllQuery(a_query, r_count);
288  }
289  else
290  {
291  return E_UNKNOWN;
292  }
293 }
294 
296 {
297  r_count = 0;
298 
299  if (!a_query)
300  {
301  return E_UNKNOWN;
302  }
303  /*
304  if(!checkConnectionStatus())
305  {
306  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
307  return E_NOT_CONNECTED;
308  }
309  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
310  */
311  PGresult * pResult = monitored_PQexec(m_dbConn, (char*)a_query);
312 
313  if(PQresultStatus(pResult) != PGRES_TUPLES_OK)
314  {
315  CAMsg::printMsg(LOG_ERR,
316  "CAAccountingDBInterface: Database Error '%s' while processing query '%s'\n",
317  PQresultErrorMessage(pResult), a_query
318  );
319  PQclear(pResult);
320  return E_UNKNOWN;
321  }
322 
323  if ( (PQntuples(pResult) != 1) || (PQgetisnull(pResult, 0, 0)))
324  {
325  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Wrong number of tuples or null value\n");
326  PQclear(pResult);
327  return E_UNKNOWN;
328  }
329 
330  r_count = atoi(PQgetvalue(pResult, 0, 0));
331  PQclear(pResult);
332  return E_SUCCESS;
333 }
334 
335 
336 /* Thread safe DB Query method */
337 SINT32 CAAccountingDBInterface::storeCostConfirmation(CAXMLCostConfirmation &cc, UINT8* ccCascade)
338 {
339  if(checkOwner())
340  {
341  return __storeCostConfirmation(cc, ccCascade);
342  }
343  else
344  {
345  return E_UNKNOWN;
346  }
347 }
352 SINT32 CAAccountingDBInterface::__storeCostConfirmation( CAXMLCostConfirmation &cc, UINT8* ccCascade )
353  {
354  #ifndef HAVE_NATIVE_UINT64
355  #warning Native UINT64 type not available - CostConfirmation Database might be non-functional
356  #endif
357  const char* previousCCQuery = "SELECT COUNT(*) FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER='%s' AND CASCADE='%s'";
358  const char* query2F = "INSERT INTO COSTCONFIRMATIONS(BYTES, XMLCC, SETTLED, ACCOUNTNUMBER, CASCADE) VALUES ('%s', '%s', '%d', '%s', '%s')";
359  const char* query3F = "UPDATE COSTCONFIRMATIONS SET BYTES='%s', XMLCC='%s', SETTLED='%d' WHERE ACCOUNTNUMBER='%s' AND CASCADE='%s'";
360  const char* tempQuery;
361 
362  UINT8 * query;
363  UINT8 * pStrCC;
364  UINT32 size;
365  UINT32 len;
366  UINT32 count;
367  PGresult * pResult;
368  UINT8 strAccountNumber[32];
369  UINT8 tmp[32];
370 
371  if(!checkConnectionStatus())
372  {
373  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
374  return E_NOT_CONNECTED;
375  }
376  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
377 
378  pStrCC = new UINT8[8192];
379  size=8192;
380  if(cc.toXMLString(pStrCC, &size)!=E_SUCCESS)
381  {
382  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstanceDBInterface: Could not transform CC to XML string!\n");
383  delete[] pStrCC;
384  pStrCC = NULL;
385  return E_UNKNOWN;
386  }
387 
388 #ifdef DEBUG
389  CAMsg::printMsg(LOG_DEBUG, "cc to store in db:%s\n",pStrCC);
390 #endif
391 
392  // Test: is there already an entry with this accountno. for the same cascade?
393  len = max(strlen(previousCCQuery), strlen(query2F));
394  len = max(len, strlen(query3F));
395  query = new UINT8[len + 32 + 32 + 1 + size + strlen((char*)ccCascade)];
396  print64(strAccountNumber,cc.getAccountNumber());
397  sprintf( (char*)query, previousCCQuery, strAccountNumber, ccCascade);
398 
399  // to receive result in binary format...
400  if (__checkCountAllQuery(query, count) != E_SUCCESS)
401  {
402  delete[] pStrCC;
403  pStrCC = NULL;
404  delete[] query;
405  query = NULL;
406  return E_UNKNOWN;
407  }
408 
409  // put query together (either insert or update)
410  print64(tmp,cc.getTransferredBytes());
411  if(count == 0)
412  {
413  tempQuery = query2F; // do insert
414  }
415  else
416  {
417  tempQuery = query3F; // do update
418  }
419  sprintf((char*)query, tempQuery, tmp, pStrCC, 0, strAccountNumber, ccCascade);
420 
421  // issue query..
422  pResult = monitored_PQexec(m_dbConn, (char*)query);
423 
424  delete[] pStrCC;
425  pStrCC = NULL;
426  if(PQresultStatus(pResult) != PGRES_COMMAND_OK) // || PQntuples(pResult) != 1)
427  {
428  CAMsg::printMsg(LOG_ERR, "Could not store CC!\n");
429  //if (PQresultStatus(pResult) != PGRES_COMMAND_OK)
430  {
431  CAMsg::printMsg(LOG_ERR,
432  "Database message '%s' while processing query '%s'\n",
433  PQresultErrorMessage(pResult), query
434  );
435  }
436  delete[] query;
437  query = NULL;
438  PQclear(pResult);
439  return E_UNKNOWN;
440  }
441  delete[] query;
442  query = NULL;
443  PQclear(pResult);
444 
445  #ifdef DEBUG
446  CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstanceDBInterface: Finished storing CC in DB.\n");
447  #endif
448  return E_SUCCESS;
449  }
450 
451 //SINT32 CAAccountingDBInterface::getUnsettledCostConfirmations(CAQueue &q, UINT8* cascadeId)
452 SINT32 CAAccountingDBInterface::getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8* cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
453 {
454  if(checkOwner())
455  {
456  return __getUnsettledCostConfirmations(resultCCs, cascadeId, nrOfCCs, a_maxCCs);
457  }
458  else
459  {
460  return E_UNKNOWN;
461  }
462 }
471 SINT32 CAAccountingDBInterface::__getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8* cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
472  {
473  const char* query= "SELECT XMLCC FROM COSTCONFIRMATIONS WHERE SETTLED=0 AND CASCADE = '%s' LIMIT %u";
474  UINT8* finalQuery;
475  PGresult* result;
476  SINT32 numTuples, i;
477  UINT8* pTmpStr;
478  CAXMLCostConfirmation* pCC;
479 
480  if(!checkConnectionStatus())
481  {
482  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
483  return E_NOT_CONNECTED;
484  }
485  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
486 
487  finalQuery = new UINT8[strlen(query)+strlen((char*)cascadeId)];
488  sprintf( (char*)finalQuery, query, cascadeId, a_maxCCs);
489 
490 #ifdef DEBUG
491  CAMsg::printMsg(LOG_DEBUG, "Getting Cost confirmations for cascade: ");
492  CAMsg::printMsg(LOG_DEBUG, (const char*) finalQuery);
493 #endif
494 
495  result = monitored_PQexec(m_dbConn, (char *)finalQuery);
496 
497  delete[] finalQuery;
498  finalQuery = NULL;
499  if(PQresultStatus(result) != PGRES_TUPLES_OK)
500  {
501  PQclear(result);
502  return E_UNKNOWN;
503  }
504  numTuples = PQntuples(result);
505  *nrOfCCs = numTuples;
506 
507  if(numTuples > 0)
508  {
509 
510  *resultCCs = new CAXMLCostConfirmation *[numTuples];
511  i = 0;
512  while(i < *nrOfCCs)
513  {
514  pTmpStr = (UINT8*) PQgetvalue(result, i, 0);
515  if( (pTmpStr!=NULL)&&
516  ( (pCC = CAXMLCostConfirmation::getInstance(pTmpStr,strlen((char*)pTmpStr)) )!=NULL))
517  {
518  (*resultCCs)[i] = pCC;
519  i++;
520  }
521  else
522  {
523  //ok, in this case we reserved a bit too much memory, but it is very unlikely and if it would happen
524  //there is no need to worry about it.
525  (*nrOfCCs)--;
526  }
527  }
528  }
529  PQclear(result);
530 
531  //CAMsg::printMsg(LOG_DEBUG, "Stop get unsettled CC\n");
532  return E_SUCCESS;
533  }
534 
535 SINT32 CAAccountingDBInterface::markAsSettled(UINT64 accountNumber, UINT8* cascadeId, UINT64 a_transferredBytes)
536 {
537  if(checkOwner())
538  {
539  return __markAsSettled(accountNumber, cascadeId, a_transferredBytes);
540  }
541  else
542  {
543  return E_UNKNOWN;
544  }
545 }
552 SINT32 CAAccountingDBInterface::__markAsSettled(UINT64 accountNumber, UINT8* cascadeId, UINT64 a_transferredBytes)
553  {
554  const char* queryF = "UPDATE COSTCONFIRMATIONS SET SETTLED=1 WHERE ACCOUNTNUMBER=%s AND BYTES=%s AND CASCADE='%s'";
555  UINT8 * query;
556  PGresult * result;
557 
558  if(!checkConnectionStatus())
559  {
560  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
561  return E_NOT_CONNECTED;
562  }
563  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
564 
565  UINT8 tmp[32], tmp2[32];
566  print64(tmp,accountNumber);
567  print64(tmp2,a_transferredBytes);
568  query = new UINT8[strlen(queryF) + 32 + 32 + strlen((char*)cascadeId)];
569  sprintf((char *)query, queryF, tmp, tmp2, cascadeId);
570  result = monitored_PQexec(m_dbConn, (char *)query);
571 
572  delete[] query;
573  query = NULL;
574  if(PQresultStatus(result) != PGRES_COMMAND_OK)
575  {
576  PQclear(result);
577  return E_UNKNOWN;
578  }
579  PQclear(result);
580 
581  return E_SUCCESS;
582  }
583 
585 {
586  if(checkOwner())
587  {
588  return __deleteCC(accountNumber, cascadeId);
589  }
590  else
591  {
592  return E_UNKNOWN;
593  }
594 }
595 
597 {
598  const char* deleteQuery = "DELETE FROM COSTCONFIRMATIONS WHERE ACCOUNTNUMBER = %s AND CASCADE='%s'";
599  UINT8* finalQuery;
600  PGresult* result;
601  SINT32 ret;
602  UINT8 temp[32];
603  print64(temp,accountNumber);
604 
605  if (!checkConnectionStatus())
606  {
607  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
608  ret = E_NOT_CONNECTED;
609  }
610  else
611  {
612  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
613 
614  finalQuery = new UINT8[strlen(deleteQuery)+ 32 + strlen((char*)cascadeId)];
615  sprintf((char *)finalQuery,deleteQuery,temp, cascadeId);
616  result = monitored_PQexec(m_dbConn, (char*)finalQuery);
617 
618  //CAMsg::printMsg(LOG_DEBUG, "%s\n",finalQuery);
619  delete[] finalQuery;
620  finalQuery = NULL;
621  if (PQresultStatus(result) != PGRES_COMMAND_OK)
622  {
623  PQclear(result);
624  ret = E_UNKNOWN;
625  }
626  else
627  {
628  PQclear(result);
629  ret = E_SUCCESS;
630  }
631  }
632 
633  if (ret == E_SUCCESS)
634  {
635  CAMsg::printMsg(LOG_INFO, "CAAccountingDBInterface: Costconfirmation for account %s was deleted!\n", temp);
636  }
637  else
638  {
639  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Could not delete account %s!\n", temp);
640  }
641 
642  return ret;
643 }
644 
645 SINT32 CAAccountingDBInterface::storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8* cascadeId)
646 {
647  if(checkOwner())
648  {
649  return __storePrepaidAmount(accountNumber, prepaidBytes, cascadeId);
650  }
651  else
652  {
653  return E_UNKNOWN;
654  }
655 }
656 /*
657  * When terminating a connection, store the amount of bytes that the JAP account has already paid for, but not used
658  */
660 {
661  const char* selectQuery = "SELECT COUNT(*) FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
662  const char* insertQuery = "INSERT INTO PREPAIDAMOUNTS(PREPAIDBYTES, ACCOUNTNUMBER, CASCADE) VALUES (%d, %s, '%s')";
663  const char* updateQuery = "UPDATE PREPAIDAMOUNTS SET PREPAIDBYTES=%d WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
664  //const char* deleteQuery = "DELETE FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER = %s AND CASCADE='%s'";
665  const char* query;
666 
667  PGresult* result;
668  UINT8* finalQuery;
669  UINT8 tmp[32];
670  UINT32 len;
671  UINT32 count;
672  print64(tmp,accountNumber);
673 
674  if(!checkConnectionStatus())
675  {
676  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
677  return E_NOT_CONNECTED;
678  }
679 
680  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
681 
682  len = max(strlen(selectQuery), strlen(insertQuery));
683  len = max(len, strlen(updateQuery));
684  finalQuery = new UINT8[len + 32 + 32 + strlen((char*)cascadeId)];
685  sprintf( (char *)finalQuery, selectQuery, tmp, cascadeId);
686 
687  if (__checkCountAllQuery(finalQuery, count) != E_SUCCESS)
688  {
689  delete[] finalQuery;
690  finalQuery = NULL;
691  /*if(!checkConnectionStatus())
692  {
693  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
694  return E_NOT_CONNECTED;
695  }*/
696  return E_UNKNOWN;
697  }
698 
699  // put query together (either insert or update)
700  if(count == 0)
701  {
702  query = insertQuery;
703  }
704  else
705  {
706  query = updateQuery;
707  }
708  sprintf((char*)finalQuery, query, prepaidBytes, tmp, cascadeId);
709  result = monitored_PQexec(m_dbConn, (char *)finalQuery);
710 
711  if (PQresultStatus(result) != PGRES_COMMAND_OK) // || PQntuples(result) != 1)
712  {
713  CAMsg::printMsg(LOG_ERR, "CAAccountungDBInterface: Saving to prepaidamounts failed!\n");
714  //if (PQresultStatus(result) != PGRES_COMMAND_OK)
715  {
716  CAMsg::printMsg(LOG_ERR,
717  "Database message '%s' while processing query '%s'\n",
718  PQresultErrorMessage(result), finalQuery
719  );
720  }
721  delete[] finalQuery;
722  finalQuery = NULL;
723  if (result)
724  {
725  PQclear(result);
726  }
727  return E_UNKNOWN;
728  }
729  delete[] finalQuery;
730  finalQuery = NULL;
731  PQclear(result);
732  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Stored %d prepaid bytes for account nr. %s \n",prepaidBytes, tmp);
733  return E_SUCCESS;
734 }
735 
736 SINT32 CAAccountingDBInterface::getPrepaidAmount(UINT64 accountNumber, UINT8* cascadeId, bool a_bDelete)
737 {
738  if(checkOwner())
739  {
740  return __getPrepaidAmount(accountNumber, cascadeId, a_bDelete);
741  }
742  else
743  {
744  return E_UNKNOWN;
745  }
746 }
747 /*
748  * When initializing a connection, retrieve the amount of prepaid, but unused, bytes the JAP account has left over from
749  * a previous connection.
750  * Will then delete this entry from the database table prepaidamounts
751  * If the account has not been connected to this cascade before, will return zero
752  */
753 SINT32 CAAccountingDBInterface::__getPrepaidAmount(UINT64 accountNumber, UINT8* cascadeId, bool a_bDelete)
754  {
755  //check for an entry for this accountnumber
756  const char* selectQuery = "SELECT PREPAIDBYTES FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s'";
757  PGresult* result;
758  UINT8* finalQuery;
759  UINT8 accountNumberAsString[32];
760  print64(accountNumberAsString,accountNumber);
761 
762  if(!checkConnectionStatus())
763  {
764  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
765  return E_NOT_CONNECTED;
766  }
767  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
768 
769  finalQuery = new UINT8[strlen(selectQuery) + 32 + strlen((char*)cascadeId)];
770  sprintf( (char *)finalQuery, selectQuery, accountNumberAsString, cascadeId);
771  result = monitored_PQexec(m_dbConn, (char *)finalQuery);
772 
773  if(PQresultStatus(result)!=PGRES_TUPLES_OK)
774  {
775  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Database error while trying to read prepaid bytes, Reason: %s\n", PQresultErrorMessage(result));
776  PQclear(result);
777  delete[] finalQuery;
778  finalQuery = NULL;
779  return E_UNKNOWN;
780  }
781 
782  if(PQntuples(result)!=1)
783  {
784  //perfectly normal, the user account simply hasnt been used with this cascade yet
785  PQclear(result);
786  delete[] finalQuery;
787  finalQuery = NULL;
788  return 0;
789  }
790  SINT32 nrOfBytes = atoi(PQgetvalue(result, 0, 0)); //first row, first column
791  PQclear(result);
792 
793  if (a_bDelete)
794  {
795  //delete entry from db
796  const char* deleteQuery = "DELETE FROM PREPAIDAMOUNTS WHERE ACCOUNTNUMBER=%s AND CASCADE='%s' ";
797  PGresult* result2;
798  print64(accountNumberAsString,accountNumber);
799  sprintf( (char *)finalQuery, deleteQuery, accountNumberAsString, cascadeId);
800 
801  result2 = monitored_PQexec(m_dbConn, (char *)finalQuery);
802 
803  if (PQresultStatus(result2) != PGRES_COMMAND_OK)
804  {
805  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Deleting read prepaidamount failed.");
806  }
807  PQclear(result2);
808  }
809 
810  delete[] finalQuery;
811  finalQuery = NULL;
812 
813  return nrOfBytes;
814  }
815 
817 {
818  if(checkOwner())
819  {
820  return __storeAccountStatus(a_accountNumber, a_statusCode);
821  }
822  else
823  {
824  return E_UNKNOWN;
825  }
826 }
827 /* upon receiving an ErrorMesage from the jpi, save the account status to the database table accountstatus
828  * uses the same error codes defined in CAXMLErrorMessage
829  */
831 {
832  const char* previousStatusQuery = "SELECT COUNT(*) FROM ACCOUNTSTATUS WHERE ACCOUNTNUMBER='%s' ";
833  //reverse order of columns, so insertQuery and updateQuery can be used with the same sprintf parameters
834  const char* insertQuery = "INSERT INTO ACCOUNTSTATUS(STATUSCODE,ACCOUNTNUMBER) VALUES ('%u', '%s')";
835  const char* updateQuery = "UPDATE ACCOUNTSTATUS SET STATUSCODE=%u WHERE ACCOUNTNUMBER=%s";
836  const char* query;
837 
838  PGresult* result;
839  UINT8* finalQuery;
840  UINT8 tmp[32];
841  UINT32 len;
842  UINT32 count;
843  print64(tmp,accountNumber);
844 
845  if(!checkConnectionStatus())
846  {
847  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
848  return E_NOT_CONNECTED;
849  }
850  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
851 
852  len = max(strlen(previousStatusQuery), strlen(insertQuery));
853  len = max(len, strlen(updateQuery));
854  finalQuery = new UINT8[len + 32 + 32 + 32];
855  sprintf( (char *)finalQuery, previousStatusQuery, tmp);
856 
857  if (__checkCountAllQuery(finalQuery, count) != E_SUCCESS)
858  {
859  delete[] finalQuery;
860  finalQuery = NULL;
861  return E_UNKNOWN;
862  }
863 
864  // put query together (either insert or update)
865  if(count == 0)
866  {
867  query = insertQuery;
868  }
869  else
870  {
871  query = updateQuery;
872  }
873  sprintf((char*)finalQuery, query, statuscode, tmp);
874  result = monitored_PQexec(m_dbConn, (char *)finalQuery);
875 
876  if (PQresultStatus(result) != PGRES_COMMAND_OK) // || PQntuples(result) != 1)
877  {
878  CAMsg::printMsg(LOG_ERR, "CAAccountungDBInterface: Saving the account status failed!\n");
879  //if (PQresultStatus(result) != PGRES_COMMAND_OK)
880  {
881  CAMsg::printMsg(LOG_ERR,
882  "Database Error '%s' while processing query '%s'\n",
883  PQresultErrorMessage(result), finalQuery
884  );
885  }
886  delete[] finalQuery;
887  finalQuery = NULL;
888  if (result)
889  {
890  PQclear(result);
891  }
892  return E_UNKNOWN;
893  }
894  delete[] finalQuery;
895  finalQuery = NULL;
896  PQclear(result);
897  CAMsg::printMsg(LOG_DEBUG, "Stored status code %u for account nr. %s \n",statuscode, tmp);
898  return E_SUCCESS;
899 }
900 
902  {
903  if(checkOwner())
904  {
905  return __clearAccountStatus(a_accountNumber);
906  }
907  else
908  {
909  return E_UNKNOWN;
910  }
911  }
912 
914  {
915  SINT32 ret = E_SUCCESS;
916  PGresult* result = NULL;
917  size_t queryMaxLen = strlen(STMT_CLEAR_ACCOUNT_STATUS) + ACCOUNT_NUMBER_SIZE; //accountnumber has exactly 12 digits
918  char* clearAccountStatusStmt=new char[queryMaxLen+1];
919  memset(clearAccountStatusStmt, 0, queryMaxLen+1);
920 
921  if( (a_accountNumber > MAX_ACCOUNTNUMBER) &&
922  (a_accountNumber < MIN_ACCOUNTNUMBER) )
923  {
924  CAMsg::printMsg(LOG_DEBUG, "Cannot clear account status: accountnumber &llu is invalid.\n",
925  a_accountNumber);
926  delete[] clearAccountStatusStmt;
927  return E_UNKNOWN;
928  }
929  snprintf(clearAccountStatusStmt, queryMaxLen, STMT_CLEAR_ACCOUNT_STATUS, a_accountNumber);
930  result = monitored_PQexec(m_dbConn, clearAccountStatusStmt);
931  if(result != NULL)
932  {
933  if (PQresultStatus(result) != PGRES_COMMAND_OK)
934  {
935  CAMsg::printMsg(LOG_DEBUG, "Clearing accountstatus for account %llu failed.\n", a_accountNumber);
936  ret = E_UNKNOWN;
937  }
938  PQclear(result);
939  delete[] clearAccountStatusStmt;
940  return ret;
941  }
942  delete[] clearAccountStatusStmt;
943  CAMsg::printMsg(LOG_DEBUG, "Clearing accountstatus for account %llu failed.\n", a_accountNumber);
944  return E_UNKNOWN;
945  }
946 
948  {
949  if(checkOwner())
950  {
951  return __getAccountStatus(a_accountNumber, a_statusCode);
952  }
953  else
954  {
955  return E_UNKNOWN;
956  }
957  }
958 
959  /* retrieve account status, e.g. to see if the user's account is empty
960  * will return 0 if everything is OK (0 is defined as status ERR_OK, but is also returned if no entry is found for this account)
961  */
963  {
964  const char* selectQuery = "SELECT STATUSCODE FROM ACCOUNTSTATUS WHERE ACCOUNTNUMBER = %s";
965  PGresult* result;
966  UINT8* finalQuery;
967  UINT8 accountNumberAsString[32];
968  print64(accountNumberAsString,accountNumber);
969 
970  if(!checkConnectionStatus())
971  {
972  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
973  return E_NOT_CONNECTED;
974  }
975  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
976 
977  a_statusCode = CAXMLErrorMessage::ERR_OK;
978 
979  finalQuery = new UINT8[strlen(selectQuery) + 32];
980  sprintf( (char *)finalQuery, selectQuery, accountNumberAsString);
981  result = monitored_PQexec(m_dbConn, (char *)finalQuery);
982 
983  delete[] finalQuery;
984  finalQuery = NULL;
985  if(PQresultStatus(result)!=PGRES_TUPLES_OK)
986  {
987  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: Database error while trying to read account status, Reason: %s\n", PQresultErrorMessage(result));
988  PQclear(result);
989  return E_UNKNOWN;
990  }
991 
992  if(PQntuples(result) == 1)
993  {
994  int statusCodeIndex = PQfnumber(result,"STATUSCODE");
995  //int expiresIndex = PQfnumber(result,"EXPIRES");
996  if(statusCodeIndex != -1 )
997  {
998  a_statusCode = atoi(PQgetvalue(result, 0, statusCodeIndex)); //first row, first column
999  }
1000  else
1001  {
1002  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: no status code found while reading account status\n");
1003  }
1004 
1005  /*if(expiresIndex != -1)
1006  {
1007  expires = strncpy(expires, (const char*)PQgetvalue(result, 0, expiresIndex), 10);
1008  }
1009  else
1010  {
1011  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: no expire date found while reading account status\n");
1012  }*/
1013  }
1014 
1015  PQclear(result);
1016 
1017  return E_SUCCESS;
1018  }
1019 
1021 {
1022  UINT32 i;
1023  UINT64 myWaitNr;
1024  CAAccountingDBInterface *returnedConnection = NULL;
1025 
1026  if(ms_pDBConnectionPool == NULL)
1027  {
1028  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: No DBConnection available. This should NEVER happen!\n");
1029  return NULL;
1030  }
1031  if(ms_pConnectionAvailable == NULL)
1032  {
1033  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnections not initialized. This should NEVER happen!\n");
1034  return NULL;
1035  }
1037  for(i=0; 1; i++)
1038  {
1039  if(ms_pDBConnectionPool[(i%MAX_DB_CONNECTIONS)] != NULL)
1040  {
1042  {
1043  returnedConnection = ms_pDBConnectionPool[(i%MAX_DB_CONNECTIONS)];
1044  break;
1045  }
1046  }
1047  if((i % MAX_DB_CONNECTIONS) == (MAX_DB_CONNECTIONS - 1) )
1048  {
1049  //wait until connection is free
1050  ms_threadWaitNr++;
1051  myWaitNr = ms_threadWaitNr;
1052 #ifdef DEBUG
1053  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Thread %x waits for connection with waitNr %Lu and %Lu Threads waiting before\n",
1054  pthread_self(), myWaitNr, (myWaitNr - ms_nextThreadNr));
1055 #endif
1056  while(ms_nextThreadNr != myWaitNr)
1057  {
1059  }
1060 #ifdef DEBUG
1061  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: Thread %x with waitNr %Lu continues\n",
1062  pthread_self(), myWaitNr);
1063 #endif
1065  {
1066  //was the last waiting thread: reset the variables
1067  ms_threadWaitNr = 0;
1068  ms_nextThreadNr = 0;
1069  }
1070  //next complete array loop turn
1071  }
1072  }
1074  if(returnedConnection != NULL)
1075  {
1076  if(!(returnedConnection->checkConnectionStatus()))
1077  {
1078  if(returnedConnection->initDBConnection() != E_SUCCESS)
1079  {
1080  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
1081  CAMsg::printMsg(LOG_WARNING, "CAAccountingDBInterface: Warning requested DB connection can not be established\n");
1082  /*returnedConnection->testAndResetOwner();
1083  return NULL;*/
1084  }
1085  else
1086  {
1087  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
1088  }
1089  }
1090  else
1091  {
1092  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
1093  }
1094  }
1095  return returnedConnection;
1096 }
1097 
1098 /*CAAccountingDBInterface *CAAccountingDBInterface::getConnectionNB()
1099 {
1100  //@todo: implementation
1101  return NULL;
1102 }*/
1103 
1105 {
1106  SINT32 ret;
1107  //@todo: implementation
1108  if(dbIf == NULL)
1109  {
1110  return E_UNKNOWN;
1111  }
1112  if(dbIf->m_pConnectionMutex == NULL)
1113  {
1114  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnection structure corrupt!\n");
1115  return E_UNKNOWN;
1116  }
1117  if(ms_pConnectionAvailable == NULL)
1118  {
1119  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnections not initialized. This should NEVER happen!\n");
1120  return E_UNKNOWN;
1121  }
1122 
1124  if(dbIf->testAndResetOwner())
1125  {
1127  {
1128  ms_nextThreadNr++;
1129 #ifdef DEBUG
1130  CAMsg::printMsg(LOG_DEBUG, "CAAccountingDBInterface: There are %Lu Threads waiting. Waking up thread with waitNr. %Lu\n",
1132 #endif
1133  //There are threads waiting
1135  }
1136  ret = E_SUCCESS;
1137  }
1138  else
1139  {
1140  ret = E_UNKNOWN;
1141  }
1143  return ret;
1144 }
1145 
1147 {
1148  bool success = false;
1150  if(m_free)
1151  {
1152  m_free = false;
1154  success = true;
1155  }
1157  return success;
1158 }
1159 
1161 {
1162  bool success = false;
1164  if(!m_free && (m_owner == CAThread::getSelfID()))
1165  {
1166  m_free = true;
1167  m_owner = 0;
1168  success = true;
1169  }
1171  return success;
1172 }
1173 
1175 {
1176  UINT32 i;
1177  SINT32 dbConnStatus;
1178 
1180 
1181  ms_threadWaitNr = 0;
1182  ms_nextThreadNr = 0;
1183 
1184  if(ms_pDBConnectionPool != NULL)
1185  {
1186  for(i=0; i < MAX_DB_CONNECTIONS; i++)
1187  {
1188  if(ms_pDBConnectionPool[i] != NULL)
1189  {
1190  //CAMsg::printMsg(LOG_WARNING, "CAAccountingDBInterface: DBConnection: "
1191  // "Already initialized connection.\n");
1192  }
1194  dbConnStatus = ms_pDBConnectionPool[i]->initDBConnection();
1195 
1196  if(dbConnStatus != E_SUCCESS)
1197  {
1198  CAMsg::printMsg(LOG_CRIT, "CAAccountingDBInterface: DBConnection initialization: "
1199  "could not connect to Database.\n");
1200  return E_UNKNOWN;
1201  }
1202  }
1203  }
1204  else
1205  { //should never happen
1206  CAMsg::printMsg(LOG_CRIT, "CAAccountingDBInterface: DBConnection initialization failed.\n");
1207  return E_UNKNOWN;
1208  }
1209  return E_SUCCESS;
1210 }
1211 
1213 {
1214  UINT32 i;
1215  SINT32 dbConnStatus, ret = E_SUCCESS;
1216  if(ms_pDBConnectionPool != NULL)
1217  {
1218  for(i=0; i < MAX_DB_CONNECTIONS; i++)
1219  {
1220  if(ms_pDBConnectionPool[i] == NULL)
1221  {
1222  //CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnection: Already cleaned up.\n");
1223  }
1224  else
1225  {
1226  dbConnStatus = ms_pDBConnectionPool[i]->terminateDBConnection();
1227  delete ms_pDBConnectionPool[i];
1228  ms_pDBConnectionPool[i] = NULL;
1229  }
1230  if(dbConnStatus != E_SUCCESS)
1231  {
1232  CAMsg::printMsg(LOG_ERR, "CAAccountingDBInterface: DBConnection cleanup: "
1233  "an error occured while closing DBConnection.\n");
1234  ret = dbConnStatus;
1235  }
1236  }
1237  }
1238  if(ms_pConnectionAvailable != NULL)
1239  {
1240  delete ms_pConnectionAvailable;
1241  ms_pConnectionAvailable = NULL;
1242  }
1243  return ret;
1244 }
1245 
1246 PGresult *CAAccountingDBInterface::monitored_PQexec(PGconn *conn, const char *query)
1247 {
1248  PGresult* result = NULL;
1249  result = PQexec(conn, query);
1250  if(!checkConnectionStatus())
1251  {
1252  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
1253  }
1254  else
1255  {
1256  MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
1257  }
1258  return result;
1259 }
1260 
1261 #endif
1262 
1263 
#define MAX_DB_CONNECTIONS
#define STMT_CLEAR_ACCOUNT_STATUS
#define MONITORING_FIRE_PAY_EVENT(e_type)
unsigned long long thread_id_t
Type of an ID for a thread which can be used to identify the current and other threads.
Definition: CAThread.hpp:70
void print64(UINT8 *buff, UINT64 num)
Definition: CAUtil.hpp:482
#define ACCOUNT_NUMBER_SIZE
Definition: StdAfx.h:769
#define MIN_ACCOUNTNUMBER
Definition: StdAfx.h:768
#define MAX_ACCOUNTNUMBER
Definition: StdAfx.h:767
#define max(a, b)
Definition: StdAfx.h:654
signed int SINT32
Definition: basetypedefs.h:132
unsigned char UINT8
Definition: basetypedefs.h:135
unsigned int UINT32
Definition: basetypedefs.h:131
SINT32 storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8 *cascadeId)
static CAAccountingDBInterface * getConnection()
static CAAccountingDBInterface * ms_pDBConnectionPool[]
SINT32 __clearAccountStatus(UINT64 a_accountNumber)
SINT32 __storePrepaidAmount(UINT64 accountNumber, SINT32 prepaidBytes, UINT8 *cascadeId)
SINT32 initDBConnection()
Initiates the database connection.
SINT32 checkCountAllQuery(UINT8 *a_query, UINT32 &r_count)
Takes and executes a query that counts databae records and tests if the result is valid.
SINT32 __markAsSettled(UINT64 accountNumber, UINT8 *cascadeId, UINT64 a_transferredBytes)
Marks this account as settled.
SINT32 storeCostConfirmation(CAXMLCostConfirmation &cc, UINT8 *ccCascade)
Creates the tables we need in the DB.
SINT32 clearAccountStatus(UINT64 a_accountNumber)
bool checkConnectionStatus()
Checks if the connection still exists and tries to reconnect if not.
SINT32 __getCostConfirmation(UINT64 accountNumber, UINT8 *cascadeId, CAXMLCostConfirmation **pCC, bool &a_bSettled)
Gets the latest cost confirmation stored for the given user account.
static volatile UINT64 ms_threadWaitNr
SINT32 __storeCostConfirmation(CAXMLCostConfirmation &cc, UINT8 *ccCascade)
stores a cost confirmation in the DB
SINT32 __getAccountStatus(UINT64 a_accountNumber, UINT32 &a_statusCode)
SINT32 __checkCountAllQuery(UINT8 *a_query, UINT32 &r_count)
SINT32 __getPrepaidAmount(UINT64 accountNumber, UINT8 *cascadeId, bool a_bDelete)
static SINT32 releaseConnection(CAAccountingDBInterface *dbIf)
static CAConditionVariable * ms_pConnectionAvailable
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)
PGconn * m_dbConn
connection to postgreSQL database
SINT32 __getUnsettledCostConfirmations(CAXMLCostConfirmation ***resultCCs, UINT8 *cascadeId, UINT32 *nrOfCCs, UINT32 a_maxCCs)
Fills the CAQueue with pointer to all non-settled cost confirmations.
SINT32 __storeAccountStatus(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...
PGresult * monitored_PQexec(PGconn *conn, const char *query)
static volatile UINT64 ms_nextThreadNr
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)
SINT32 terminateDBConnection()
Terminates the database connection.
UINT16 getDatabasePort()
SINT32 broadcast()
Signals this object.
SINT32 wait()
Waits for a signal or for a timeout.
static CACmdLnOptions * getOptions()
static SINT32 printMsg(UINT32 typ, const char *format,...)
Writes a given message to the log.
Definition: CAMsg.cpp:251
SINT32 unlock()
Definition: CAMutex.hpp:52
SINT32 lock()
Definition: CAMutex.hpp:41
static thread_id_t getSelfID()
Definition: CAThread.hpp:201
static const UINT32 ERR_OK
const SINT32 E_SUCCESS
Definition: errorcodes.hpp:2
#define E_NOT_CONNECTED
Definition: errorcodes.hpp:22
#define E_NOT_FOUND
Definition: errorcodes.hpp:24
#define E_UNKNOWN
Definition: errorcodes.hpp:3
UINT16 len
Definition: typedefs.hpp:0