Mixe for Privacy and Anonymity in the Internet
CAFirstMixChannelList.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 #if !defined ONLY_LOCAL_PROXY || defined INCLUDE_FIRST_MIX
31 #include "CAUtil.hpp"
32 #include "CAMsg.hpp"
33 #include "CAThread.hpp"
34 #define MAX_HASH_KEY 8200 //8113
35 
36 #ifdef PAYMENT
37  #include "CAAccountingInstance.hpp"
38 #endif
39 
41 
42 
44  {
47  for(int i=0;i<MAX_HASH_KEY;i++)
48  {
50  memset(m_HashTable[i],0,sizeof(fmHashTableEntry));
51 #ifdef PAYMENT
53 #endif
54  }
57 #ifdef PAYMENT
58  m_listTimoutHead = NULL;
59  m_listTimoutFoot = NULL;
60 #endif
62  memset(m_HashTableOutChannels,0,sizeof(LP_fmChannelListEntry)*0x10000);
63 #ifdef DO_TRACE
64  m_aktAlloc=m_maxAlloc=0;
65 #endif
66 #ifdef DELAY_USERS
70  m_pDelayBuckets=new volatile UINT32*[MAX_POLLFD];
71  memset(m_pDelayBuckets,0,sizeof(UINT32*)*MAX_POLLFD);
73  m_pThreadDelayBucketsLoop=new CAThread((UINT8*)"Delay Channel Thread");
77 #endif
78  }
79 
81  {
82 #ifdef DELAY_USERS
87  delete m_pMutexDelayChannel;
88  m_pMutexDelayChannel = NULL;
89  delete []m_pDelayBuckets;
90  m_pDelayBuckets = NULL;
91 #endif
92  for(int i=0;i<MAX_HASH_KEY;i++)
93  {
94 
95 #ifdef PAYMENT
96  delete m_HashTable[i]->cleanupNotifier;
97  m_HashTable[i]->cleanupNotifier = NULL;
98 #endif
99  delete m_HashTable[i];
100  m_HashTable[i] = NULL;
101  }
102  delete []m_HashTable;
103  m_HashTable = NULL;
104  delete []m_HashTableOutChannels;
105  m_HashTableOutChannels = NULL;
106  }
107 
115 #ifndef LOG_DIALOG
116 fmHashTableEntry* CAFirstMixChannelList::add(CAMuxSocket* pMuxSocket,const UINT8 peerIP[4],CAQueue* pQueueSend,UINT8* controlChannelKeySent,UINT8* controlChannelKeyRecv)
117 #else
118 fmHashTableEntry* CAFirstMixChannelList::add(CAMuxSocket* pMuxSocket,const UINT8 peerIP[4],CAQueue* pQueueSend,UINT8* strDialog)
119 #endif
120  {
121  INIT_STACK;
122  BEGIN_STACK("CAFirstMixChannelList::add");
123 
124  if(pMuxSocket==NULL)
125  {
126  FINISH_STACK("CAFirstMixChannelList::add (null socket)");
127  return NULL;
128  }
129  SINT32 hashkey=pMuxSocket->getHashKey();
130  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
131  {
132  FINISH_STACK("CAFirstMixChannelList::add (invalid hash key)");
133  return NULL;
134  }
135  m_Mutex.lock();
136  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
137  if(pHashTableEntry->pMuxSocket!=NULL) //the entry in the hashtable for this socket (hashkey) must be empty
138  {
139  FINISH_STACK("CAFirstMixChannelList::add (socket exists)");
140  m_Mutex.unlock();
141  return NULL;
142  }
143 
144  //SAVE_STACK("CAFirstMixChannelList::add", "initialising table entry");
145 #ifdef CH_LOG_STUDY
146  pHashTableEntry->channelOpenedLastIntervalTS = 0;
147 #endif
148  pHashTableEntry->pMuxSocket=pMuxSocket;
149  pHashTableEntry->pQueueSend=pQueueSend;
150  pHashTableEntry->pControlMessageQueue = new CAQueue();
151  pHashTableEntry->pControlChannelDispatcher = new CAControlChannelDispatcher(pHashTableEntry->pControlMessageQueue,controlChannelKeyRecv,controlChannelKeySent);
152  pHashTableEntry->uAlreadySendPacketSize=-1;
153  pHashTableEntry->cNumberOfChannels=0;
154 #ifdef LOG_TRAFFIC_PER_USER
155  pHashTableEntry->trafficIn=0;
156  pHashTableEntry->trafficOut=0;
157  getcurrentTimeMillis(pHashTableEntry->timeCreated);
158 #endif
159 #ifdef LOG_DIALOG
160  pHashTableEntry->strDialog=new UINT8[strlen((char*)strDialog)+1];
161  strcpy((char*)pHashTableEntry->strDialog,(char*)strDialog);
162 #endif
163  // TODO Collisions? Is the id still used somewhere?
164  //Yes it is --> for logging to match login /logout
165  //collisions in a hard seens are an issue, but are very unlikely; and because it is only for logging it does not really matter...
166  getRandom(&(pHashTableEntry->id));
167 
168 #ifdef PAYMENT
169  pHashTableEntry->pAccountingInfo=NULL;
170 #endif
171  SAVE_STACK("CAFirstMixChannelList::add", "copying peer IP");
172  memcpy(pHashTableEntry->peerIP,peerIP,4);
173 #if defined(DATA_RETENTION_LOG) || defined(LOG_CRIME)
174  pHashTableEntry->peerPort=pMuxSocket->getCASocket()->getPeerPort();
175 #endif
176 #ifdef DELAY_USERS
177  m_pMutexDelayChannel->lock();
178  pHashTableEntry->delayBucket=m_u32DelayChannelUnlimitTraffic; //can always send some first packets
179  for(UINT32 i=0;i<MAX_POLLFD;i++)
180  {
181  if(m_pDelayBuckets[i]==NULL)
182  {
183  pHashTableEntry->delayBucketID=i;
184  break;
185  }
186  }
187  m_pDelayBuckets[pHashTableEntry->delayBucketID]=&pHashTableEntry->delayBucket;
188  m_pMutexDelayChannel->unlock();
189 #endif
190 
191  SAVE_STACK("CAFirstMixChannelList::add", "inserting in connection list");
192  //now insert the new connection in the list of all open connections
193  if(m_listHashTableHead==NULL) //if first one
194  {
195  pHashTableEntry->list_HashEntries.next=NULL;
196  }
197  else
198  {//add to the head of the double linked list
199  pHashTableEntry->list_HashEntries.next=m_listHashTableHead;
200  m_listHashTableHead->list_HashEntries.prev=pHashTableEntry;
201  }
202  pHashTableEntry->list_HashEntries.prev=NULL;
203  m_listHashTableHead=pHashTableEntry;
204 
205  SAVE_STACK("CAFirstMixChannelList::add", "inserting in timout list");
206  // insert in timeout list; entries are added to the foot of the list
207 #ifdef PAYMENT
208  pHashTableEntry->bRecoverTimeout = true;
209  pHashTableEntry->kickoutSendRetries = MAX_KICKOUT_RETRIES;
210  /* Hot fix: push timeout entry explicitly to avoid
211  * confusion, when timeout occurs during AI login
212  */
213  //pushTimeoutEntry_internal(pHashTableEntry);
214 #endif
215  m_Mutex.unlock();
216 
217  FINISH_STACK("CAFirstMixChannelList::add");
218 
219  return pHashTableEntry;
220  }
221 
223 #define MAX_NUMBER_OF_CHANNELS CHANNELS_PER_CLIENT
224 
235  CASymChannelCipher* pCipher,HCHANNEL* channelOut)
236  {
237  if(pMuxSocket==NULL||channelOut==NULL)
238  return E_UNKNOWN;
239  SINT32 hashkey=pMuxSocket->getHashKey();
240  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
241  return E_UNKNOWN;
242  m_Mutex.lock();
243  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
244  if(pHashTableEntry->pMuxSocket==NULL||pHashTableEntry->cNumberOfChannels>=MAX_NUMBER_OF_CHANNELS)
245  {
246  #define ERR_MSG_TO_MANY_CHANNELS "More than " STR(MAX_NUMBER_OF_CHANNELS) " channels!\n"
248  m_Mutex.unlock();
249  return E_UNKNOWN;
250  }
251  fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
252 #ifndef DO_TRACE
253  fmChannelListEntry* pNewEntry=new fmChannelListEntry;
254 #else
255  fmChannelListEntry* pNewEntry=newChannelListEntry();
256 #endif
257  memset(pNewEntry,0,sizeof(fmChannelListEntry));
258  pNewEntry->pCipher=pCipher;
259  pNewEntry->channelIn=channelIn;
260 
261  do
262  {
263  getRandom(channelOut); //get new Random OUT-CHANNEL-ID
264  } while(*channelOut<256||get_intern_without_lock(*channelOut)!=NULL); //until it is unused...
265  pNewEntry->channelOut=*channelOut;
266  pNewEntry->bIsSuspended=false;
267  pNewEntry->pHead=pHashTableEntry;
268 
269 #ifdef LOG_CHANNEL
270  pNewEntry->packetsInFromUser=0;
271  pNewEntry->packetsOutToUser=0;
272 #endif
273 #ifdef SSL_HACK
274  pNewEntry->downStreamBytes = 0;
275 #endif
276 #ifdef ANON_DEBUG_MODE
277  pNewEntry->bDebug = false;
278 #endif
279 
280 
281 
282  //add to the channel list for the given connection
283  if(pEntry==NULL) //First Entry to the channel list
284  {
285  pNewEntry->list_InChannelPerSocket.next=NULL;
286  pNewEntry->list_InChannelPerSocket.prev=NULL;
287  }
288  else
289  {
290  pNewEntry->list_InChannelPerSocket.next=pEntry;
291  pNewEntry->list_InChannelPerSocket.prev=NULL;
292  pEntry->list_InChannelPerSocket.prev=pNewEntry;
293  }
294  pHashTableEntry->pChannelList=pNewEntry;
295 
296  //add to the out-channel list
297  hashkey=(*channelOut)&0x0000FFFF;
298  pEntry=m_HashTableOutChannels[hashkey];
299  if(pEntry!=NULL) //Hash Table Bucket Over run....
300  {
301  pNewEntry->list_OutChannelHashTable.prev=NULL;
302  pNewEntry->list_OutChannelHashTable.next=pEntry;
303  pEntry->list_OutChannelHashTable.prev=pNewEntry;
304  }
305  m_HashTableOutChannels[hashkey]=pNewEntry;
306  pHashTableEntry->cNumberOfChannels++;
307  m_Mutex.unlock();
308  return E_SUCCESS;
309  }
310 
311 
318  {
319  if(pMuxSocket==NULL)
320  return NULL;
321  SINT32 hashkey=pMuxSocket->getHashKey();
322  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
323  return NULL;
324  m_Mutex.lock();
325  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
326  m_Mutex.unlock();
327  return pHashTableEntry;
328  }
329 
337  {
338  if(pMuxSocket==NULL)
339  return NULL;
340  SINT32 hashkey=pMuxSocket->getHashKey();
341  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
342  return NULL;
343  m_Mutex.lock();
344  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
345  fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
346  while(pEntry!=NULL)
347  {
348  if(pEntry->channelIn==channelIn)
349  {
350  m_Mutex.unlock();
351  return pEntry;
352  }
353  pEntry=pEntry->list_InChannelPerSocket.next;
354  }
355  m_Mutex.unlock();
356  return NULL;
357  }
358 #ifdef PAYMENT
359 
361 {
362  return popTimeoutEntry(false);
363 }
364 
366 {
368 
369  m_Mutex.lock();
370  ret = popTimeoutEntry_internal(a_bForce);
371  m_Mutex.unlock();
372 
373  return ret;
374 }
375 
377 {
378  bool ret = false;
379 
380  m_Mutex.lock();
381  ret = isTimedOut_internal(pHashTableEntry);
382  m_Mutex.unlock();
383 
384  return ret;
385 }
386 
388 {
389  bool ret = false;
390  m_Mutex.lock();
391  ret = isKickoutForced_internal(pHashTableEntry);
392  m_Mutex.unlock();
393  return ret;
394 }
395 void CAFirstMixChannelList::setKickoutForced(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
396 {
397  m_Mutex.lock();
398  setKickoutForced_internal(pHashTableEntry, kickoutForced);
399  m_Mutex.unlock();
400 }
401 
402 #ifdef PAYMENT
408 bool CAFirstMixChannelList::forceKickout(fmHashTableEntry* pHashTableEntry, const XERCES_CPP_NAMESPACE::DOMDocument *pErrDoc)
409 {
410  bool ret = false;
411  m_Mutex.lock();
412  ret = (pHashTableEntry->pMuxSocket != NULL);
413  if(ret)
414  {
415  if(pErrDoc != NULL)
416  {
417  //NOTE: accessing the control channel in this case works without further locking,
418  //because the control channel is only deleted when the Dispatcher deletes all channels.
419  //This happens when the table entry is removed by CAFirstMixChannelList::remove
420  //which locks over m_Mutex.
421  pHashTableEntry->pAccountingInfo->pControlChannel->sendXMLMessage(pErrDoc);
422  }
423  setKickoutForced_internal(pHashTableEntry, KICKOUT_FORCED);
424  }
425  m_Mutex.unlock();
426  return ret;
427 }
428 #endif
429 
430 //be careful: has no locking and parameter checks
432 {
433  return (pHashTableEntry->list_TimeoutHashEntries.timoutSecs <= time(NULL));
434 }
435 
437 {
438  return !(pHashTableEntry->bRecoverTimeout);
439 }
440 
441 void CAFirstMixChannelList::setKickoutForced_internal(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
442 {
443  if(!pHashTableEntry->bRecoverTimeout && !kickoutForced )
444  {
445  CAMsg::printMsg(LOG_WARNING, "Try to switch back from forced kickout. A forced kickout cannot be undone!\n");
446  }
447  else
448  {
449  pHashTableEntry->bRecoverTimeout = !kickoutForced;
450  }
451 
452 }
453 
455 {
456  fmHashTableEntry* pHashTableEntry;
457 
458  if (m_listTimoutHead == NULL)
459  {
460  // there are not entries in the list
461  return NULL;
462  }
463 
464  pHashTableEntry = m_listTimoutHead;
465  if (a_bForce || isTimedOut_internal(pHashTableEntry))
466  {
467  if (removeFromTimeoutList(pHashTableEntry) == E_SUCCESS)
468  {
469  return pHashTableEntry;
470  }
471  else
472  {
473  CAMsg::printMsg(LOG_CRIT,
474  "CAFirstMixChannelList:popTimeoutEntry_internal: Could not remove expired entry from timeout list!\n");
475  }
476  }
477 
478  return NULL;
479 }
480 #endif
481 
482 #ifdef PAYMENT
484 {
485  SINT32 ret;
486 
487  m_Mutex.lock();
488  ret = pushTimeoutEntry_internal(pHashTableEntry, kickoutForced);
489  m_Mutex.unlock();
490 
491  return ret;
492 }
493 
494 
496 {
497  fmHashTableEntry* pHashTableEntry;
498  UINT32 count = 0;
499 
500  for (pHashTableEntry = m_listTimoutHead; pHashTableEntry != NULL;
501  count++, pHashTableEntry = pHashTableEntry->list_TimeoutHashEntries.next);
502 
503  return count;
504 }
505 #endif
506 
507 #ifdef PAYMENT
513 {
514  if (pHashTableEntry == NULL)
515  {
516  return E_UNKNOWN;
517  }
518 
519 
520  /*if(isKickoutForced_internal(pHashTableEntry))
521  {
522  return E_SUCCESS;
523  }*/
524 
525  INIT_STACK;
526  BEGIN_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal");
527 
528  //CAMsg::printMsg(LOG_DEBUG,"Entries in timeout list before push: %d\n", countTimeoutEntries());
529 
530  pHashTableEntry->list_TimeoutHashEntries.timoutSecs = time(NULL) + EXPIRATION_TIME_SECS;
531 
532  //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "removing from timeout list");
533  // remove from timeout list if needed before adding it to the end
534  removeFromTimeoutList(pHashTableEntry);
535  setKickoutForced_internal(pHashTableEntry, kickoutForced);
536  if (m_listTimoutFoot == NULL)
537  {
538  //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "new first entry");
539 
540  // this is the first entry in the list
541  pHashTableEntry->list_TimeoutHashEntries.prev = NULL;
542  m_listTimoutHead = pHashTableEntry;
543  }
544  else
545  {
546  //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "new last entry");
547  // this is the new last entry in the list
548  m_listTimoutFoot->list_TimeoutHashEntries.next = pHashTableEntry;
549  pHashTableEntry->list_TimeoutHashEntries.prev = m_listTimoutFoot;
550  }
551  pHashTableEntry->list_TimeoutHashEntries.next = NULL;
552  m_listTimoutFoot = pHashTableEntry;
553 
554  //CAMsg::printMsg(LOG_DEBUG,"Entries in timeout list after push: %d\n", countTimeoutEntries());
555 
556  FINISH_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal");
557  //CAMsg::printMsg(LOG_DEBUG, "CAFirstMixA: pushed entry %x!\n", pHashTableEntry);
558  return E_SUCCESS;
559 
560 }
561 #endif
562 
563 #ifdef PAYMENT
565 {
566  if (pHashTableEntry == NULL)
567  {
568  return E_UNKNOWN;
569  }
570 
571  //CAMsg::printMsg(LOG_DEBUG, "CAFirstMixA: removing entry %x!\n", pHashTableEntry);
572 
573  if (m_listTimoutHead == NULL || m_listTimoutFoot == NULL)
574  {
575  // there is no entry in the list; therefore this entry does not need to be removed
576  return E_SUCCESS;
577  }
578 
579  if (pHashTableEntry->list_TimeoutHashEntries.prev == NULL &&
580  pHashTableEntry->list_TimeoutHashEntries.next == NULL &&
581  m_listTimoutHead != pHashTableEntry)
582  {
583  // this entry is not in the list; it does not need to be removed
584  return E_SUCCESS;
585  }
586 
587  if(m_listTimoutHead == pHashTableEntry) //if entry is the head of the connection list
588  {
589  if(m_listTimoutFoot == pHashTableEntry) //if entry is also the last (so the only one in the list..)
590  {
591  //list is now empty
592  m_listTimoutHead = NULL;
593  m_listTimoutFoot = NULL;
594  }
595  else
596  {
597  //remove the head of the list
598  m_listTimoutHead = pHashTableEntry->list_TimeoutHashEntries.next;
599  }
600  }
601  else
602  { //the connection is not the head of the list
603  if(pHashTableEntry->list_TimeoutHashEntries.next == NULL)
604  {
605  //the connection is the last element in the list
606  m_listTimoutFoot = pHashTableEntry->list_TimeoutHashEntries.prev;
608  }
609  else
610  {
611  //it is a simple middle element
612  if (pHashTableEntry->list_TimeoutHashEntries.prev == NULL)
613  {
614  CAMsg::printMsg(LOG_CRIT, "CAFirstMixChannelList:removeFromTimeoutList: No previous element!!\n");
615  }
616  else
617  {
619  }
620  if (pHashTableEntry->list_TimeoutHashEntries.next == NULL)
621  {
622  CAMsg::printMsg(LOG_CRIT, "CAFirstMixChanelList:removeFromTimeoutList: No next element!!\n");
623  }
624  else
625  {
627  }
628  }
629  }
630  pHashTableEntry->list_TimeoutHashEntries.prev = NULL;
631  pHashTableEntry->list_TimeoutHashEntries.next = NULL;
632 
633  return E_SUCCESS;
634 }
635 #endif
636 
644  {
645  if(pMuxSocket==NULL)
646  return E_UNKNOWN;
647  SINT32 hashkey=pMuxSocket->getHashKey();
648  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
649  return E_UNKNOWN;
650  m_Mutex.lock();
651  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
652  if(pHashTableEntry->pMuxSocket==NULL) //this connection is not in the list
653  {
654  m_Mutex.unlock();
655  return E_UNKNOWN;
656  }
657  #ifdef DELAY_USERS
659  m_pDelayBuckets[pHashTableEntry->delayBucketID]=NULL;
661  #endif
663  delete pHashTableEntry->pControlChannelDispatcher; //deletes the dispatcher and all associated control channels
664  delete pHashTableEntry->pControlMessageQueue;
665  pHashTableEntry->pControlChannelDispatcher = NULL;
666  pHashTableEntry->pControlMessageQueue = NULL;
667  if(m_listHashTableNext==pHashTableEntry) //adjust the enumeration over all connections (@see getNext())
668  m_listHashTableNext=pHashTableEntry->list_HashEntries.next;
669 
670  if(pHashTableEntry->list_HashEntries.prev==NULL) //if entry is the head of the connection list
671  {
672  if(pHashTableEntry->list_HashEntries.next==NULL) //if entry is also the last (so the only one in the list..)
673  {
674  m_listHashTableHead=NULL; //list is now empty
675  }
676  else
677  {//remove the head of the list
678  m_listHashTableHead=pHashTableEntry->list_HashEntries.next;
680  }
681  }
682  else
683  { //the connection is not the head of the list
684  if(pHashTableEntry->list_HashEntries.next==NULL)
685  {//the connection is the last element in the list
686  pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=NULL;
687  }
688  else
689  {//its a simple middle element
690  pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=pHashTableEntry->list_HashEntries.next;
691  pHashTableEntry->list_HashEntries.next->list_HashEntries.prev=pHashTableEntry->list_HashEntries.prev;
692  }
693  }
694 
695 
696 #ifdef PAYMENT
697  removeFromTimeoutList(pHashTableEntry);
698 #endif
699 
700  fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
701  fmChannelListEntry* pTmpEntry;
702  while(pEntry!=NULL)//for all channels....
703  {
704  //remove the out channel form the out channel hast table
705  hashkey=pEntry->channelOut&0x0000FFFF;
706  pTmpEntry=m_HashTableOutChannels[hashkey];
707  while(pTmpEntry!=NULL)
708  {
709  if(pTmpEntry->channelOut==pEntry->channelOut)
710  {//we have found the entry
711  if(pTmpEntry->list_OutChannelHashTable.prev==NULL) //it's the head
712  {
713  if(pTmpEntry->list_OutChannelHashTable.next==NULL)
714  {//it's also the last Element
715  m_HashTableOutChannels[hashkey]=NULL; //empty this hash bucket
716  }
717  else
718  {
721  }
722  }
723  else
724  {//not the head
725  if(pTmpEntry->list_OutChannelHashTable.next==NULL)
726  {//but the last
728  }
729  else
730  {//a middle element
733  }
734  }
735  break;
736  }
737  pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
738  }
739 
740  pTmpEntry=pEntry->list_InChannelPerSocket.next;
741 #ifndef DO_TRACE
742  delete pEntry;
743  pEntry = NULL;
744 #else
745  deleteChannelListEntry(pEntry);
746 #endif
747  pEntry=pTmpEntry;
748  }
749 /* already done by pHashTableEntry->pControlChannelDispatcher->deleteAllControlChannels();
750 #ifdef PAYMENT
751  // cleanup accounting information
752  CAAccountingInstance::cleanupTableEntry(pHashTableEntry);
753 #endif
754 */
755 #ifdef LOG_DIALOG
756  delete[] pHashTableEntry->strDialog;
757  pHashTableEntry->strDialog = NULL;
758 #endif
759 #ifdef PAYMENT
760  CAConditionVariable *rescue = pHashTableEntry->cleanupNotifier;
761 #endif
762  //TODO: a bit more precise reference cleanup
763  memset(pHashTableEntry,0,sizeof(fmHashTableEntry)); //'delete' the connection from the connection hash table
764 
765 #ifdef PAYMENT
766  pHashTableEntry->cleanupNotifier = rescue;
767  pHashTableEntry->cleanupNotifier->lock();
768  pHashTableEntry->cleanupNotifier->signal();
769  pHashTableEntry->cleanupNotifier->unlock();
770 #endif
771  m_Mutex.unlock();
772  return E_SUCCESS;
773  }
774 
775 
776 #ifdef NEW_MIX_TYPE
777 /* some additional methods for TypeB first mixes */
778 
786 SINT32 CAFirstMixChannelList::removeClientPart(CAMuxSocket* pMuxSocket)
787  {
788  if(pMuxSocket==NULL)
789  return E_UNKNOWN;
790  SINT32 hashkey=pMuxSocket->getSocket();
791  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
792  return E_UNKNOWN;
793  m_Mutex.lock();
794  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
795  if(pHashTableEntry->pMuxSocket==NULL) //this connection is not in the list
796  {
797  m_Mutex.unlock();
798  return E_UNKNOWN;
799  }
800  #ifdef DELAY_USERS
802  m_pDelayBuckets[pHashTableEntry->delayBucketID]=NULL;
804  #endif
806  delete pHashTableEntry->pControlChannelDispatcher; //deletes the dispatcher and all associated control channels
807  pHashTableEntry->pControlChannelDispatcher = NULL;
808  if(m_listHashTableNext==pHashTableEntry) //adjust the enumeration over all connections (@see getNext())
809  m_listHashTableNext=pHashTableEntry->list_HashEntries.next;
810 
811  if(pHashTableEntry->list_HashEntries.prev==NULL) //if entry is the head of the connection list
812  {
813  if(pHashTableEntry->list_HashEntries.next==NULL) //if entry is also the last (so the only one in the list..)
814  {
815  m_listHashTableHead=NULL; //list is now empty
816  }
817  else
818  {//remove the head of the list
819  m_listHashTableHead=pHashTableEntry->list_HashEntries.next;
821  }
822  }
823  else
824  {//the connection is not the head of the list
825  if(pHashTableEntry->list_HashEntries.next==NULL)
826  {//the connection is the last element in the list
827  pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=NULL;
828  }
829  else
830  {//its a simple middle element
831  pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=pHashTableEntry->list_HashEntries.next;
832  pHashTableEntry->list_HashEntries.next->list_HashEntries.prev=pHashTableEntry->list_HashEntries.prev;
833  }
834  }
835 
836  removeFromTimeoutList(pHashTableEntry);
837 
838 
839  fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
840  while(pEntry!=NULL)//for all channels....
841  {
842  /* leave a dummy-entry in the out-channels-table until we receive a
843  * CLOSE-message for the channel from the last mix (else we could
844  * re-use it, while the last mix is still using the old channel),
845  * therefore set the the pointer for the in-channel-part to NULL
846  */
847  pEntry->pHead = NULL;
848  pEntry = pEntry->list_InChannelPerSocket.next;
849  }
850  #ifdef PAYMENT
851  // cleanup accounting information
853  #endif
854  memset(pHashTableEntry,0,sizeof(fmHashTableEntry)); //'delete' the connection from the connection hash table
855  m_Mutex.unlock();
856  return E_SUCCESS;
857  }
858 
864 void CAFirstMixChannelList::removeVacantOutChannel(fmChannelListEntry* pEntry) {
865  if (pEntry != NULL) {
866  if (pEntry->pHead == NULL) {
867  /* must be a vacant channel */
868  m_Mutex.lock();
869  fmChannelListEntry* pTmpEntry;
870  /* check whether the enty is in the out-channel-table */
871  SINT32 hashkey = pEntry->channelOut & 0x0000FFFF;
872  pTmpEntry = m_HashTableOutChannels[hashkey];
873  while (pTmpEntry != NULL) {
874  if (pTmpEntry->channelOut == pEntry->channelOut) {
875  //we have found the entry
876  if (pTmpEntry->list_OutChannelHashTable.prev==NULL) { //it's the head
877  if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
878  //it's also the last Element
879  m_HashTableOutChannels[hashkey] = NULL; //empty this hash bucket
880  }
881  else {
884  }
885  }
886  else {
887  //not the head
888  if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
889  //but the last
891  }
892  else {
893  //a middle element
896  }
897  }
898  break;
899  }
900  pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
901  }
902  /* entry is not in the table any more */
903  #ifndef DO_TRACE
904  delete pEntry;
905  pEntry = NULL;
906  #else
907  deleteChannelListEntry(pEntry);
908  #endif
909  m_Mutex.unlock();
910  }
911  }
912 }
913 
918 void CAFirstMixChannelList::cleanVacantOutChannels() {
919  m_Mutex.lock();
920  SINT32 hashkey = 0;
921  do {
922  fmChannelListEntry* pTmpEntry = m_HashTableOutChannels[hashkey];
923  while (pTmpEntry != NULL) {
924  if (pTmpEntry->pHead == NULL) {
925  /* we have found a vacant channel */
926  if (pTmpEntry->list_OutChannelHashTable.prev==NULL) { //it's the head
927  if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
928  //it's also the last Element
929  m_HashTableOutChannels[hashkey] = NULL; //empty this hash bucket
930  }
931  else {
934  }
935  }
936  else {
937  //not the head
938  if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
939  //but the last
941  }
942  else {
943  //a middle element
946  }
947  }
948  /* entry is removed from the table, now delete the channel-cipher */
949  delete pTmpEntry->pCipher;
950  pTmpEntry->pCipher = NULL;
951  fmChannelListEntry* pRemoveEntry = pTmpEntry;
952  pTmpEntry = pTmpEntry->list_OutChannelHashTable.next;
953  /* delete the entry */
954  #ifndef DO_TRACE
955  delete pRemoveEntry;
956  pRemoveEntry = NULL;
957  #else
958  deleteChannelListEntry(pEntry);
959  #endif
960  }
961  else {
962  /* not a vacant channel -> try the next channel in the hashtable-line */
963  pTmpEntry = pTmpEntry->list_OutChannelHashTable.next;
964  }
965  }
966  /* we have processed a whole line of the channel-table -> process the next
967  * one
968  */
969  hashkey = (hashkey + 1) & 0x0000FFFF;
970  }
971  while (hashkey != 0);
972  /* we have processed the whole out-channel-table */
973  m_Mutex.unlock();
974 }
975 #endif //NEW_MIX_TYPE (TypeB first mixes)
976 
984  {
985  if(pMuxSocket==NULL)
986  return E_UNKNOWN;
987  SINT32 hashkey=pMuxSocket->getHashKey();
988  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
989  return E_UNKNOWN;
990  m_Mutex.lock();
991  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
992  if(pHashTableEntry->pMuxSocket==NULL)
993  {
994  m_Mutex.unlock();
995  return E_UNKNOWN;
996  }
997  fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
998  while(pEntry!=NULL)
999  {
1000  if(pEntry->channelIn==channelIn) //search for the channel
1001  {
1002  hashkey=pEntry->channelOut&0x0000FFFF; //remove the out channel from the out channel hash table
1003  fmChannelListEntry*pTmpEntry=m_HashTableOutChannels[hashkey];
1004  while(pTmpEntry!=NULL)
1005  {
1006  if(pTmpEntry->channelOut==pEntry->channelOut)
1007  {//found it in the out channel hash table
1008  if(pTmpEntry->list_OutChannelHashTable.prev==NULL) //head
1009  {
1010  if(pTmpEntry->list_OutChannelHashTable.next==NULL)
1011  {
1012  m_HashTableOutChannels[hashkey]=NULL;
1013  }
1014  else
1015  {
1016 
1019  }
1020  }
1021  else
1022  {
1023  if(pTmpEntry->list_OutChannelHashTable.next==NULL)
1024  {//last element
1026  }
1027  else
1028  {//middle element
1031  }
1032  }
1033  break;
1034  }
1035  pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
1036  }
1037 
1038  //remove the channel from the channel hast table
1039  if(pEntry->list_InChannelPerSocket.prev==NULL) //head
1040  {
1041  if(pEntry->list_InChannelPerSocket.next==NULL)
1042  {//the only element
1043  pHashTableEntry->pChannelList=NULL;
1044  }
1045  else
1046  {
1048  pHashTableEntry->pChannelList=pEntry->list_InChannelPerSocket.next;
1049  }
1050  }
1051  else
1052  {
1053  if(pEntry->list_InChannelPerSocket.next==NULL)
1054  {//the last element
1056  }
1057  else
1058  {//a middle element
1061  }
1062  }
1063  #ifndef DO_TRACE
1064  delete pEntry;
1065  pEntry = NULL;
1066  #else
1067  deleteChannelListEntry(pEntry);
1068  #endif
1069  pHashTableEntry->cNumberOfChannels--;
1070  m_Mutex.unlock();
1071  return E_SUCCESS;
1072  }
1073  pEntry=pEntry->list_InChannelPerSocket.next; //try next channel
1074  }
1075  m_Mutex.unlock();
1076  return E_UNKNOWN;//not found
1077  }
1078 
1085  {
1086  m_Mutex.lock();
1087  if(m_listHashTableHead!=NULL)
1089  else
1090  m_listHashTableNext=NULL;
1091  m_Mutex.unlock();
1092  return m_listHashTableHead;
1093  }
1094 
1101  {
1102  m_Mutex.lock();
1104  if(m_listHashTableNext!=NULL)
1106  m_Mutex.unlock();
1107  return tmpEntry;
1108  }
1109 
1117  {
1118  if(pMuxSocket==NULL)
1119  return NULL;
1120  SINT32 hashkey=pMuxSocket->getHashKey();
1121  if(hashkey>MAX_HASH_KEY-1||hashkey<0)
1122  return NULL;
1123  fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
1124  return pHashTableEntry->pChannelList;
1125  }
1126 
1134  {
1135  if(pEntry==NULL)
1136  return NULL;
1137  return pEntry->list_InChannelPerSocket.next;
1138  }
1139 
1141  {
1143  CAMuxSocket *pMuxSocket=new CAMuxSocket(OFB);
1144  pMuxSocket->getCASocket()->create();
1145  UINT8 peerIP[4];
1146 #ifndef LOG_DIALOG
1147  pList->add(pMuxSocket,peerIP,NULL,NULL,NULL);
1148 #else
1149  pList->add(pMuxSocket,peerIP,NULL,(UINT8*)"1");
1150 #endif
1151 #if defined(HAVE_CRTDBG)
1152  _CrtMemState s1, s2, s3;
1153  _CrtMemCheckpoint( &s1 );
1154 #endif
1155  UINT32 /*channelIn,*/i,channelOut;
1156  for(i=0;i<50;i++)
1157  pList->addChannel(pMuxSocket,i,NULL,&channelOut);
1158  for(i=0;i<50;i++)
1159  pList->removeChannel(pMuxSocket,i);
1160 #if defined(HAVE_CRTDBG)
1161  _CrtMemCheckpoint( &s2 );
1162  if ( _CrtMemDifference( &s3, &s1, &s2 ) )
1163  _CrtMemDumpStatistics( &s3 );
1164 #endif
1165 
1166  pList->remove(pMuxSocket);
1167  delete pMuxSocket;
1168  pMuxSocket = NULL;
1169  delete pList;
1170  pList = NULL;
1171  return E_SUCCESS;
1172  }
1173 
1174 #ifdef DELAY_USERS
1176  {
1177  INIT_STACK;
1178  BEGIN_STACK("CAFirstMixChannelList::fml_loopDelayBuckets");
1179 
1180  CAFirstMixChannelList* pChannelList=(CAFirstMixChannelList*)param;
1181  volatile UINT32** pDelayBuckets=pChannelList->m_pDelayBuckets;
1182  while(pChannelList->m_bDelayBucketsLoopRun)
1183  {
1184  pChannelList->m_pMutexDelayChannel->lock();
1185  UINT32 u32BucketGrow=pChannelList->m_u32DelayChannelBucketGrow;
1186  UINT32 u32MaxBucket=u32BucketGrow*10;
1187  for(UINT32 i=0;i<MAX_POLLFD;i++)
1188  {
1189  if(pDelayBuckets[i]!=NULL&&*(pDelayBuckets[i])<u32MaxBucket)
1190  {
1191  *(pDelayBuckets[i])+=u32BucketGrow;
1192  }
1193  }
1194  pChannelList->m_pMutexDelayChannel->unlock();
1196  }
1197 
1198  FINISH_STACK("CAFirstMixChannelList::fml_loopDelayBuckets");
1199 
1201  }
1202 
1204  {
1206  if(delayBucketID < MAX_POLLFD)
1207  {
1208  if(m_pDelayBuckets[delayBucketID] != NULL)
1209  {
1210  *(m_pDelayBuckets[delayBucketID]) -= ( (*(m_pDelayBuckets[delayBucketID])) > 0 ) ? 1 : 0;
1211  }
1212  /*CAMsg::printMsg(LOG_DEBUG,"DelayBuckets decrementing ID %u downto %u\n",
1213  delayBucketID, (*(m_pDelayBuckets[delayBucketID])) );*/
1214  }
1216  }
1217 
1219  {
1220  bool ret = false;
1222  if(delayBucketID < MAX_POLLFD)
1223  {
1224  if(m_pDelayBuckets[delayBucketID] != NULL)
1225  {
1226  ret = ( (*(m_pDelayBuckets[delayBucketID])) > 0 );
1227  }
1228  }
1230  return ret;
1231  }
1232 
1233  void CAFirstMixChannelList::setDelayParameters(UINT32 unlimitTraffic,UINT32 bucketGrow,UINT32 intervall)
1234  {
1236  CAMsg::printMsg(LOG_DEBUG,"CAFirstMixChannelList - Set new traffic limit per user- unlimit: %u bucketgrow: %u intervall %u\n",
1237  unlimitTraffic,bucketGrow,intervall);
1238  m_u32DelayChannelUnlimitTraffic=unlimitTraffic;
1239  m_u32DelayChannelBucketGrow=bucketGrow;
1241  for(UINT32 i=0;i<MAX_POLLFD;i++)
1242  if(m_pDelayBuckets[i]!=NULL)
1245  }
1246 
1247 #endif
1248 #endif //ONLY_LOCAL_PROXY
#define MAX_HASH_KEY
THREAD_RETURN fml_loopDelayBuckets(void *param)
#define MAX_NUMBER_OF_CHANNELS
The maximum number of channels allowed per connection.
#define ERR_MSG_TO_MANY_CHANNELS
struct t_firstmixchannellist fmChannelListEntry
#define KICKOUT_FORCED
struct t_fmhashtableentry fmHashTableEntry
#define MAX_KICKOUT_RETRIES
#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 getcurrentTimeMillis(UINT64 &u64Time)
Gets the current Systemtime in milli seconds.
Definition: CAUtil.cpp:252
SINT32 getRandom(UINT32 *val)
Gets 32 random bits.
Definition: CAUtil.cpp:346
SINT32 msSleep(UINT32 ms)
Sleeps ms milliseconds.
Definition: CAUtil.cpp:406
#define DELAY_USERS_BUCKET_GROW
Definition: StdAfx.h:160
#define THREAD_RETURN
Definition: StdAfx.h:540
#define THREAD_RETURN_SUCCESS
Definition: StdAfx.h:542
#define MAX_POLLFD
Definition: StdAfx.h:192
#define DELAY_USERS_BUCKET_GROW_INTERVALL
Definition: StdAfx.h:159
#define DELAY_USERS_TRAFFIC
Definition: StdAfx.h:154
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.
static SINT32 cleanupTableEntry(fmHashTableEntry *pHashEntry)
This should always be called when closing a JAP connection to cleanup the data structures.
SINT32 signal()
Signals this object.
This class "dispatches" messages which it receives via proccessMixPacket() to the associated control ...
void deleteAllControlChannels(void)
Deregisters all control channels and calls delete on every registered control channel object.
Data structure that stores all information about the currently open Mix channels.
fmChannelListEntry * getFirstChannelForSocket(CAMuxSocket *pMuxSocket)
Gets the first channel for a given connection.
void setDelayParameters(UINT32 unlimitTraffic, UINT32 bucketGrow, UINT32 intervall)
fmHashTableEntry * getFirst()
Gets the first connection of all connections in the list.
LP_fmChannelListEntry * m_HashTableOutChannels
The Hash-Table of all out-channels.
volatile UINT32 ** m_pDelayBuckets
bool isKickoutForced(fmHashTableEntry *pHashTableEntry)
bool isTimedOut_internal(fmHashTableEntry *pHashTableEntry)
SINT32 removeFromTimeoutList(fmHashTableEntry *pHashTableEntry)
fmHashTableEntry * m_listTimoutHead
Pointer to the head of the timout list of all connections.
SINT32 addChannel(CAMuxSocket *pMuxSocket, HCHANNEL channelIn, CASymChannelCipher *pCipher, HCHANNEL *channelOut)
Adds a new channel for a given connection to the channel list.
static const SINT32 EXPIRATION_TIME_SECS
fmChannelListEntry * get(CAMuxSocket *pMuxSocket, HCHANNEL channelIn)
Returns the information for a given Input-Channel-ID.
fmHashTableEntry * m_listHashTableNext
Next Element in the enumeration of all connections.
fmHashTableEntry * getNext()
Gets the next entry in the connections-list.
fmChannelListEntry * get_intern_without_lock(HCHANNEL channelOut)
Gets the in-channel and all associated information for the given out-channel.
fmHashTableEntry * m_listHashTableHead
Pointer to the head of a list of all connections.
friend THREAD_RETURN fml_loopDelayBuckets(void *)
bool forceKickout(fmHashTableEntry *pHashTableEntry, const XERCES_CPP_NAMESPACE::DOMDocument *pErrDoc)
forces a kickout for this entry if the entry is still valid and sends an errorMessage via the control...
fmHashTableEntry * popTimeoutEntry_internal(bool a_bForce)
SINT32 removeChannel(CAMuxSocket *pMuxSocket, HCHANNEL channelIn)
Removes a single channel from the list.
bool isTimedOut(fmHashTableEntry *pHashTableEntry)
fmHashTableEntry * m_listTimoutFoot
bool isKickoutForced_internal(fmHashTableEntry *pHashTableEntry)
void decDelayBuckets(UINT32 delayBucketID)
volatile UINT32 m_u32DelayChannelBucketGrowIntervall
fmChannelListEntry * getNextChannel(fmChannelListEntry *pEntry)
Gets the next channel for a given connection.
fmHashTableEntry * add(CAMuxSocket *pMuxSocket, const UINT8 peerIP[4], CAQueue *pQueueSend, UINT8 *controlChannelKeyRecv, UINT8 *controlChannelKeySent)
Adds a new TCP/IP connection (a new user) to the channel list.
volatile UINT32 m_u32DelayChannelBucketGrow
SINT32 remove(CAMuxSocket *pMuxSocket)
Removes all channels, which belongs to the given connection and the connection itself from the list.
void setKickoutForced_internal(fmHashTableEntry *pHashTableEntry, bool kickoutForced)
void setKickoutForced(fmHashTableEntry *pHashTableEntry, bool kickoutForced)
LP_fmHashTableEntry * m_HashTable
The Hash-Table of all connections.
fmHashTableEntry * popTimeoutEntry()
SINT32 pushTimeoutEntry(fmHashTableEntry *pHashTableEntry, bool kickoutForced=!KICKOUT_FORCED)
adds the entry to the timeout queue with mutex
bool hasDelayBuckets(UINT32 delayBucketID)
CAMutex m_Mutex
This mutex is used in all functions and makes them thread safe.
SINT32 pushTimeoutEntry_internal(fmHashTableEntry *pHashTableEntry, bool kickoutForced=!KICKOUT_FORCED)
adds the entry to the timeout queue
volatile UINT32 m_u32DelayChannelUnlimitTraffic
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
SOCKET getSocket()
Definition: CAMuxSocket.hpp:92
SINT32 getHashKey()
Returns a Hashkey which uniquely identifies this socket.
Definition: CAMuxSocket.hpp:52
CASocket * getCASocket()
Definition: CAMuxSocket.hpp:84
This is a simple FIFO-Queue.
Definition: CAQueue.hpp:50
virtual SINT32 getPeerPort()
Definition: CASocket.cpp:830
virtual SINT32 create()
Definition: CASocket.cpp:73
SINT32 start(void *param, bool bDaemon=false, bool bSilent=false)
Starts the execution of the main function of this thread.
Definition: CAThread.cpp:115
SINT32 setMainLoop(THREAD_MAIN_TYP fnc)
Sets the main function which will be executed within this thread.
Definition: CAThread.hpp:148
SINT32 join()
Waits for the main function to finish execution.
Definition: CAThread.cpp:187
const SINT32 E_SUCCESS
Definition: errorcodes.hpp:2
#define E_UNKNOWN
Definition: errorcodes.hpp:3
CAAccountingControlChannel * pControlChannel
a pointer to the user-specific control channel object
Definition: typedefs.hpp:330
CASymChannelCipher * pCipher
struct t_firstmixchannellist * prev
struct t_firstmixchannellist * next
struct t_firstmixchannellist::@2 list_OutChannelHashTable
struct t_firstmixchannellist::@3 list_InChannelPerSocket
volatile UINT32 delayBucketID
struct t_fmhashtableentry * prev
CAControlChannelDispatcher * pControlChannelDispatcher
volatile UINT32 delayBucket
CountryID of this IP Address.
CAConditionVariable * cleanupNotifier
struct t_fmhashtableentry::@1 list_TimeoutHashEntries
struct t_firstmixchannellist * pChannelList
tAiAccountingInfo * pAccountingInfo
struct t_fmhashtableentry * next
struct t_fmhashtableentry::@0 list_HashEntries
UINT32 HCHANNEL
Definition: typedefs.hpp:34