Mixe for Privacy and Anonymity in the Internet
CAFirstMixChannelList.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team
00003 All rights reserved.
00004 Redistribution and use in source and binary forms, with or without modification,
00005 are permitted provided that the following conditions are met:
00006 
00007   - Redistributions of source code must retain the above copyright notice,
00008     this list of conditions and the following disclaimer.
00009 
00010   - Redistributions in binary form must reproduce the above copyright notice,
00011     this list of conditions and the following disclaimer in the documentation and/or
00012     other materials provided with the distribution.
00013 
00014   - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
00015     may be used to endorse or promote products derived from this software without specific
00016     prior written permission.
00017 
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
00020 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00021 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
00022 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00025 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00027 */
00028 #include "StdAfx.h"
00029 #ifndef ONLY_LOCAL_PROXY
00030 #include "CAFirstMixChannelList.hpp"
00031 #include "CAUtil.hpp"
00032 #include "CAMsg.hpp"
00033 #include "CAThread.hpp"
00034 #define MAX_HASH_KEY 8200 //8113
00035 
00036 #ifdef PAYMENT
00037   #include "CAAccountingInstance.hpp"
00038 #endif
00039 
00040 const SINT32 CAFirstMixChannelList::EXPIRATION_TIME_SECS = 300; // 5 minutes
00041 
00042 
00043 CAFirstMixChannelList::CAFirstMixChannelList()
00044   {
00045     m_HashTable=new LP_fmHashTableEntry[MAX_HASH_KEY];
00046     memset(m_HashTable,0,sizeof(LP_fmHashTableEntry)*MAX_HASH_KEY);
00047     for(int i=0;i<MAX_HASH_KEY;i++)
00048       {
00049         m_HashTable[i]=new fmHashTableEntry;
00050         memset(m_HashTable[i],0,sizeof(fmHashTableEntry));
00051 #ifdef PAYMENT
00052         m_HashTable[i]->cleanupNotifier = new CAConditionVariable();
00053 #endif
00054       }
00055     m_listHashTableHead=NULL;
00056     m_listHashTableNext=NULL;
00057 #ifdef PAYMENT
00058     m_listTimoutHead = NULL;
00059     m_listTimoutFoot = NULL;
00060 #endif
00061     m_HashTableOutChannels=new LP_fmChannelListEntry[0x10000];
00062     memset(m_HashTableOutChannels,0,sizeof(LP_fmChannelListEntry)*0x10000);
00063 #ifdef DO_TRACE
00064   m_aktAlloc=m_maxAlloc=0;
00065 #endif
00066 #ifdef DELAY_USERS
00067     m_u32DelayChannelUnlimitTraffic=DELAY_USERS_TRAFFIC;
00068     m_u32DelayChannelBucketGrow=DELAY_USERS_BUCKET_GROW;
00069     m_u32DelayChannelBucketGrowIntervall=DELAY_USERS_BUCKET_GROW_INTERVALL;
00070     m_pDelayBuckets=new volatile UINT32*[MAX_POLLFD];
00071     memset(m_pDelayBuckets,0,sizeof(UINT32*)*MAX_POLLFD);
00072     m_pMutexDelayChannel=new CAMutex();
00073     m_pThreadDelayBucketsLoop=new CAThread((UINT8*)"Delay Channel Thread");
00074     m_bDelayBucketsLoopRun=true;
00075     m_pThreadDelayBucketsLoop->setMainLoop(fml_loopDelayBuckets);
00076     m_pThreadDelayBucketsLoop->start(this);
00077 #endif
00078   }
00079 
00080 CAFirstMixChannelList::~CAFirstMixChannelList()
00081   {
00082 #ifdef DELAY_USERS
00083     m_bDelayBucketsLoopRun=false;
00084     m_pThreadDelayBucketsLoop->join();
00085     delete m_pThreadDelayBucketsLoop;
00086     m_pThreadDelayBucketsLoop = NULL;
00087     delete m_pMutexDelayChannel;
00088     m_pMutexDelayChannel = NULL;
00089     delete []m_pDelayBuckets;
00090     m_pDelayBuckets = NULL;
00091 #endif
00092     for(int i=0;i<MAX_HASH_KEY;i++)
00093         {
00094 
00095 #ifdef PAYMENT
00096           delete m_HashTable[i]->cleanupNotifier;
00097           m_HashTable[i]->cleanupNotifier = NULL;
00098 #endif
00099           delete m_HashTable[i];
00100           m_HashTable[i] = NULL;
00101         }
00102     delete []m_HashTable;
00103     m_HashTable = NULL;
00104     delete []m_HashTableOutChannels;
00105     m_HashTableOutChannels = NULL;
00106   }
00107 
00115 #ifndef LOG_DIALOG
00116 fmHashTableEntry* CAFirstMixChannelList::add(CAMuxSocket* pMuxSocket,const UINT8 peerIP[4],CAQueue* pQueueSend,UINT8* controlChannelKeySent,UINT8* controlChannelKeyRecv)
00117 #else
00118 fmHashTableEntry* CAFirstMixChannelList::add(CAMuxSocket* pMuxSocket,const UINT8 peerIP[4],CAQueue* pQueueSend,UINT8* strDialog)
00119 #endif
00120   {
00121     INIT_STACK;
00122     BEGIN_STACK("CAFirstMixChannelList::add");
00123 
00124     if(pMuxSocket==NULL)
00125     {
00126       FINISH_STACK("CAFirstMixChannelList::add (null socket)");
00127       return NULL;
00128     }
00129     SINT32 hashkey=pMuxSocket->getHashKey();
00130     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00131     {
00132       FINISH_STACK("CAFirstMixChannelList::add (invalid hash key)");
00133       return NULL;
00134     }
00135     m_Mutex.lock();
00136     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00137     if(pHashTableEntry->pMuxSocket!=NULL) //the entry in the hashtable for this socket (hashkey) must be empty
00138     {
00139       FINISH_STACK("CAFirstMixChannelList::add (socket exists)");
00140       m_Mutex.unlock();
00141       return NULL;
00142     }
00143 
00144     //SAVE_STACK("CAFirstMixChannelList::add", "initialising table entry");
00145 #ifdef CH_LOG_STUDY
00146     pHashTableEntry->channelOpenedLastIntervalTS = 0;
00147 #endif
00148     pHashTableEntry->pMuxSocket=pMuxSocket;
00149     pHashTableEntry->pQueueSend=pQueueSend;
00150     pHashTableEntry->pControlMessageQueue = new CAQueue();
00151     pHashTableEntry->pControlChannelDispatcher = new CAControlChannelDispatcher(pHashTableEntry->pControlMessageQueue,controlChannelKeyRecv,controlChannelKeySent);
00152     pHashTableEntry->uAlreadySendPacketSize=-1;
00153     pHashTableEntry->cNumberOfChannels=0;
00154 #ifdef LOG_TRAFFIC_PER_USER
00155     pHashTableEntry->trafficIn=0;
00156     pHashTableEntry->trafficOut=0;
00157     getcurrentTimeMillis(pHashTableEntry->timeCreated);
00158 #endif
00159 #ifdef LOG_DIALOG
00160     pHashTableEntry->strDialog=new UINT8[strlen((char*)strDialog)+1];
00161     strcpy((char*)pHashTableEntry->strDialog,(char*)strDialog);
00162 #endif
00163     // TODO Collisions? Is the id still used somewhere?
00164     //Yes it is --> for logging to match login /logout
00165     //collisions in a hard seens are an issue, but are very unlikely; and because it is only for logging it does not really matter...
00166     getRandom(&(pHashTableEntry->id));
00167 
00168 #ifdef PAYMENT
00169     pHashTableEntry->pAccountingInfo=NULL;
00170 #endif
00171 
00172     SAVE_STACK("CAFirstMixChannelList::add", "copying peer IP");
00173     memcpy(pHashTableEntry->peerIP,peerIP,4);
00174 #ifdef DATA_RETENTION_LOG
00175     pHashTableEntry->peerPort=pMuxSocket->getCASocket()->getPeerPort();
00176 #endif
00177 #ifdef DELAY_USERS
00178     m_pMutexDelayChannel->lock();
00179     pHashTableEntry->delayBucket=m_u32DelayChannelUnlimitTraffic; //can always send some first packets
00180     for(UINT32 i=0;i<MAX_POLLFD;i++)
00181       {
00182         if(m_pDelayBuckets[i]==NULL)
00183           {
00184             pHashTableEntry->delayBucketID=i;
00185             break;
00186           }
00187       }
00188     m_pDelayBuckets[pHashTableEntry->delayBucketID]=&pHashTableEntry->delayBucket;
00189     m_pMutexDelayChannel->unlock();
00190 #endif
00191 
00192     SAVE_STACK("CAFirstMixChannelList::add", "inserting in connection list");
00193     //now insert the new connection in the list of all open connections
00194     if(m_listHashTableHead==NULL) //if first one
00195     {
00196       pHashTableEntry->list_HashEntries.next=NULL;
00197     }
00198     else
00199     {//add to the head of the double linked list
00200       pHashTableEntry->list_HashEntries.next=m_listHashTableHead;
00201       m_listHashTableHead->list_HashEntries.prev=pHashTableEntry;
00202     }
00203     pHashTableEntry->list_HashEntries.prev=NULL;
00204     m_listHashTableHead=pHashTableEntry;
00205 
00206     SAVE_STACK("CAFirstMixChannelList::add", "inserting in timout list");
00207     // insert in timeout list; entries are added to the foot of the list
00208 #ifdef PAYMENT
00209     pHashTableEntry->bRecoverTimeout = true;
00210     pHashTableEntry->kickoutSendRetries = MAX_KICKOUT_RETRIES;
00211     /* Hot fix: push timeout entry explicitly to avoid
00212      * confusion, when timeout occurs during AI login
00213      */
00214     //pushTimeoutEntry_internal(pHashTableEntry);
00215 #endif
00216     m_Mutex.unlock();
00217 
00218     FINISH_STACK("CAFirstMixChannelList::add");
00219 
00220     return pHashTableEntry;
00221   }
00222 
00224 #define MAX_NUMBER_OF_CHANNELS CHANNELS_PER_CLIENT
00225 
00235 SINT32 CAFirstMixChannelList::addChannel(CAMuxSocket* pMuxSocket,HCHANNEL channelIn,
00236                                   CASymCipher* pCipher,HCHANNEL* channelOut)
00237   {
00238     if(pMuxSocket==NULL||channelOut==NULL)
00239       return E_UNKNOWN;
00240     SINT32 hashkey=pMuxSocket->getHashKey();
00241     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00242       return E_UNKNOWN;
00243     m_Mutex.lock();
00244     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00245     if(pHashTableEntry->pMuxSocket==NULL||pHashTableEntry->cNumberOfChannels>=MAX_NUMBER_OF_CHANNELS)
00246       {
00247         CAMsg::printMsg(LOG_DEBUG,"More than 50 channels!\n");
00248         m_Mutex.unlock();
00249         return E_UNKNOWN;
00250       }
00251     fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
00252 #ifndef DO_TRACE
00253     fmChannelListEntry* pNewEntry=new fmChannelListEntry;
00254 #else
00255     fmChannelListEntry* pNewEntry=newChannelListEntry();
00256 #endif
00257     memset(pNewEntry,0,sizeof(fmChannelListEntry));
00258     pNewEntry->pCipher=pCipher;
00259     pNewEntry->channelIn=channelIn;
00260 
00261     do
00262       {
00263         getRandom(channelOut); //get new Random OUT-CHANNEL-ID
00264       } while(*channelOut<256||get_intern_without_lock(*channelOut)!=NULL); //until it is unused...
00265     pNewEntry->channelOut=*channelOut;
00266     pNewEntry->bIsSuspended=false;
00267     pNewEntry->pHead=pHashTableEntry;
00268 
00269 #ifdef LOG_CHANNEL
00270     pNewEntry->packetsInFromUser=0;
00271     pNewEntry->packetsOutToUser=0;
00272 #endif
00273 #ifdef SSL_HACK
00274     pNewEntry->downStreamBytes = 0;
00275 #endif
00276 
00277 
00278 
00279     //add to the channel list for the given connection
00280     if(pEntry==NULL) //First Entry to the channel list
00281     {
00282       pNewEntry->list_InChannelPerSocket.next=NULL;
00283       pNewEntry->list_InChannelPerSocket.prev=NULL;
00284     }
00285     else
00286     {
00287       pNewEntry->list_InChannelPerSocket.next=pEntry;
00288       pNewEntry->list_InChannelPerSocket.prev=NULL;
00289       pEntry->list_InChannelPerSocket.prev=pNewEntry;
00290     }
00291     pHashTableEntry->pChannelList=pNewEntry;
00292 
00293     //add to the out-channel list
00294     hashkey=(*channelOut)&0x0000FFFF;
00295     pEntry=m_HashTableOutChannels[hashkey];
00296     if(pEntry!=NULL) //Hash Table Bucket Over run....
00297       {
00298         pNewEntry->list_OutChannelHashTable.prev=NULL;
00299         pNewEntry->list_OutChannelHashTable.next=pEntry;
00300         pEntry->list_OutChannelHashTable.prev=pNewEntry;
00301       }
00302     m_HashTableOutChannels[hashkey]=pNewEntry;
00303     pHashTableEntry->cNumberOfChannels++;
00304     m_Mutex.unlock();
00305     return E_SUCCESS;
00306   }
00307 
00308 
00314 fmHashTableEntry* CAFirstMixChannelList::get(CAMuxSocket* pMuxSocket)
00315   {
00316     if(pMuxSocket==NULL)
00317       return NULL;
00318     SINT32 hashkey=pMuxSocket->getHashKey();
00319     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00320       return NULL;
00321     m_Mutex.lock();
00322     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00323     m_Mutex.unlock();
00324     return pHashTableEntry;
00325   }
00326 
00333 fmChannelListEntry* CAFirstMixChannelList::get(CAMuxSocket* pMuxSocket,HCHANNEL channelIn)
00334   {
00335     if(pMuxSocket==NULL)
00336       return NULL;
00337     SINT32 hashkey=pMuxSocket->getHashKey();
00338     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00339       return NULL;
00340     m_Mutex.lock();
00341     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00342     fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
00343     while(pEntry!=NULL)
00344       {
00345         if(pEntry->channelIn==channelIn)
00346           {
00347             m_Mutex.unlock();
00348             return pEntry;
00349           }
00350         pEntry=pEntry->list_InChannelPerSocket.next;
00351       }
00352     m_Mutex.unlock();
00353     return NULL;
00354   }
00355 #ifdef PAYMENT
00356 
00357 inline fmHashTableEntry* CAFirstMixChannelList::popTimeoutEntry()
00358 {
00359   return popTimeoutEntry(false);
00360 }
00361 
00362 fmHashTableEntry* CAFirstMixChannelList::popTimeoutEntry(bool a_bForce)
00363 {
00364   fmHashTableEntry* ret;
00365 
00366   m_Mutex.lock();
00367   ret = popTimeoutEntry_internal(a_bForce);
00368   m_Mutex.unlock();
00369 
00370   return ret;
00371 }
00372 
00373 bool CAFirstMixChannelList::isTimedOut(fmHashTableEntry* pHashTableEntry)
00374 {
00375   bool ret = false;
00376 
00377   m_Mutex.lock();
00378   ret = isTimedOut_internal(pHashTableEntry);
00379   m_Mutex.unlock();
00380 
00381   return ret;
00382 }
00383 
00384 bool CAFirstMixChannelList::isKickoutForced(fmHashTableEntry* pHashTableEntry)
00385 {
00386   bool ret = false;
00387   m_Mutex.lock();
00388   ret = isKickoutForced_internal(pHashTableEntry);
00389   m_Mutex.unlock();
00390   return ret;
00391 }
00392 void CAFirstMixChannelList::setKickoutForced(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
00393 {
00394   m_Mutex.lock();
00395   setKickoutForced_internal(pHashTableEntry, kickoutForced);
00396   m_Mutex.unlock();
00397 }
00398 
00399 #ifdef PAYMENT
00400 
00405 bool CAFirstMixChannelList::forceKickout(fmHashTableEntry* pHashTableEntry, const XERCES_CPP_NAMESPACE::DOMDocument *pErrDoc)
00406 {
00407   bool ret = false;
00408   m_Mutex.lock();
00409   ret = (pHashTableEntry->pMuxSocket != NULL);
00410   if(ret)
00411   {
00412     if(pErrDoc != NULL)
00413     {
00414       //NOTE: accessing the control channel in this case works without further locking,
00415       //because the control channel is only deleted when the Dispatcher deletes all channels.
00416       //This happens when the table entry is removed by CAFirstMixChannelList::remove
00417       //which locks over m_Mutex.
00418       pHashTableEntry->pAccountingInfo->pControlChannel->sendXMLMessage(pErrDoc);
00419     }
00420     setKickoutForced_internal(pHashTableEntry, KICKOUT_FORCED);
00421   }
00422   m_Mutex.unlock();
00423   return ret;
00424 }
00425 #endif
00426 
00427 //be careful: has no locking and parameter checks
00428 inline bool CAFirstMixChannelList::isTimedOut_internal(fmHashTableEntry* pHashTableEntry)
00429 {
00430   return (pHashTableEntry->list_TimeoutHashEntries.timoutSecs <= time(NULL));
00431 }
00432 
00433 inline bool CAFirstMixChannelList::isKickoutForced_internal(fmHashTableEntry* pHashTableEntry)
00434 {
00435   return !(pHashTableEntry->bRecoverTimeout);
00436 }
00437 
00438 void CAFirstMixChannelList::setKickoutForced_internal(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
00439 {
00440   if(!pHashTableEntry->bRecoverTimeout && !kickoutForced )
00441   {
00442     CAMsg::printMsg(LOG_WARNING, "Try to switch back from forced kickout. A forced kickout cannot be undone!\n");
00443   }
00444   else
00445   {
00446     pHashTableEntry->bRecoverTimeout = !kickoutForced;
00447   }
00448 
00449 }
00450 
00451 fmHashTableEntry* CAFirstMixChannelList::popTimeoutEntry_internal(bool a_bForce)
00452 {
00453   fmHashTableEntry* pHashTableEntry;
00454 
00455   if (m_listTimoutHead == NULL)
00456   {
00457     // there are not entries in the list
00458     return NULL;
00459   }
00460 
00461   pHashTableEntry = m_listTimoutHead;
00462   if (a_bForce || isTimedOut_internal(pHashTableEntry))
00463   {
00464     if (removeFromTimeoutList(pHashTableEntry) == E_SUCCESS)
00465     {
00466       return pHashTableEntry;
00467     }
00468     else
00469     {
00470       CAMsg::printMsg(LOG_CRIT,
00471         "CAFirstMixChannelList:popTimeoutEntry_internal: Could not remove expired entry from timeout list!\n");
00472     }
00473   }
00474 
00475   return NULL;
00476 }
00477 #endif
00478 
00479 #ifdef PAYMENT
00480 SINT32 CAFirstMixChannelList::pushTimeoutEntry(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
00481 {
00482   SINT32 ret;
00483 
00484   m_Mutex.lock();
00485   ret = pushTimeoutEntry_internal(pHashTableEntry, kickoutForced);
00486   m_Mutex.unlock();
00487 
00488   return ret;
00489 }
00490 
00491 
00492 UINT32 CAFirstMixChannelList::countTimeoutEntries()
00493 {
00494   fmHashTableEntry* pHashTableEntry;
00495   UINT32 count = 0;
00496 
00497   for (pHashTableEntry = m_listTimoutHead; pHashTableEntry != NULL;
00498     count++, pHashTableEntry = pHashTableEntry->list_TimeoutHashEntries.next);
00499 
00500   return count;
00501 }
00502 #endif
00503 
00504 #ifdef PAYMENT
00505 
00509 SINT32 CAFirstMixChannelList::pushTimeoutEntry_internal(fmHashTableEntry* pHashTableEntry, bool kickoutForced)
00510 {
00511   if (pHashTableEntry == NULL)
00512   {
00513     return E_UNKNOWN;
00514   }
00515 
00516 
00517   /*if(isKickoutForced_internal(pHashTableEntry))
00518   {
00519     return E_SUCCESS;
00520   }*/
00521 
00522   INIT_STACK;
00523   BEGIN_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal");
00524 
00525   //CAMsg::printMsg(LOG_DEBUG,"Entries in timeout list before push: %d\n", countTimeoutEntries());
00526 
00527   pHashTableEntry->list_TimeoutHashEntries.timoutSecs = time(NULL) + EXPIRATION_TIME_SECS;
00528 
00529   //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "removing from timeout list");
00530   // remove from timeout list if needed before adding it to the end
00531   removeFromTimeoutList(pHashTableEntry);
00532   setKickoutForced_internal(pHashTableEntry, kickoutForced);
00533   if (m_listTimoutFoot == NULL)
00534   {
00535     //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "new first entry");
00536 
00537     // this is the first entry in the list
00538     pHashTableEntry->list_TimeoutHashEntries.prev = NULL;
00539     m_listTimoutHead = pHashTableEntry;
00540   }
00541   else
00542   {
00543     //SAVE_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal", "new last entry");
00544     // this is the new last entry in the list
00545     m_listTimoutFoot->list_TimeoutHashEntries.next = pHashTableEntry;
00546     pHashTableEntry->list_TimeoutHashEntries.prev = m_listTimoutFoot;
00547   }
00548   pHashTableEntry->list_TimeoutHashEntries.next = NULL;
00549   m_listTimoutFoot = pHashTableEntry;
00550 
00551   //CAMsg::printMsg(LOG_DEBUG,"Entries in timeout list after push: %d\n", countTimeoutEntries());
00552 
00553   FINISH_STACK("CAFirstMixChannelList::pushTimeoutEntry_internal");
00554   //CAMsg::printMsg(LOG_DEBUG, "CAFirstMixA: pushed entry %x!\n", pHashTableEntry);
00555   return E_SUCCESS;
00556 
00557 }
00558 #endif
00559 
00560 #ifdef PAYMENT
00561 SINT32 CAFirstMixChannelList::removeFromTimeoutList(fmHashTableEntry* pHashTableEntry)
00562 {
00563   if (pHashTableEntry == NULL)
00564   {
00565     return E_UNKNOWN;
00566   }
00567 
00568   //CAMsg::printMsg(LOG_DEBUG, "CAFirstMixA: removing entry %x!\n", pHashTableEntry);
00569 
00570   if (m_listTimoutHead == NULL || m_listTimoutFoot == NULL)
00571   {
00572     // there is no entry in the list; therefore this entry does not need to be removed
00573     return E_SUCCESS;
00574   }
00575 
00576   if (pHashTableEntry->list_TimeoutHashEntries.prev == NULL &&
00577     pHashTableEntry->list_TimeoutHashEntries.next == NULL &&
00578     m_listTimoutHead != pHashTableEntry)
00579   {
00580     // this entry is not in the list; it does not need to be removed
00581     return E_SUCCESS;
00582   }
00583 
00584   if(m_listTimoutHead == pHashTableEntry) //if entry is the head of the connection list
00585   {
00586     if(m_listTimoutFoot == pHashTableEntry) //if entry is also the last (so the only one in the list..)
00587     {
00588       //list is now empty
00589       m_listTimoutHead = NULL;
00590       m_listTimoutFoot = NULL;
00591     }
00592     else
00593     {
00594       //remove the head of the list
00595       m_listTimoutHead = pHashTableEntry->list_TimeoutHashEntries.next;
00596     }
00597   }
00598   else
00599   { //the connection is not the head of the list
00600     if(pHashTableEntry->list_TimeoutHashEntries.next == NULL)
00601     {
00602       //the connection is the last element in the list
00603       m_listTimoutFoot = pHashTableEntry->list_TimeoutHashEntries.prev;
00604       m_listTimoutFoot->list_TimeoutHashEntries.next = NULL;
00605     }
00606     else
00607     {
00608       //it is a simple middle element
00609       if (pHashTableEntry->list_TimeoutHashEntries.prev == NULL)
00610       {
00611         CAMsg::printMsg(LOG_CRIT, "CAFirstMixChannelList:removeFromTimeoutList: No previous element!!\n");
00612       }
00613       else
00614       {
00615         pHashTableEntry->list_TimeoutHashEntries.prev->list_TimeoutHashEntries.next = pHashTableEntry->list_TimeoutHashEntries.next;
00616       }
00617       if (pHashTableEntry->list_TimeoutHashEntries.next == NULL)
00618       {
00619         CAMsg::printMsg(LOG_CRIT, "CAFirstMixChanelList:removeFromTimeoutList: No next element!!\n");
00620       }
00621       else
00622       {
00623         pHashTableEntry->list_TimeoutHashEntries.next->list_TimeoutHashEntries.prev = pHashTableEntry->list_TimeoutHashEntries.prev;
00624       }
00625     }
00626   }
00627   pHashTableEntry->list_TimeoutHashEntries.prev = NULL;
00628   pHashTableEntry->list_TimeoutHashEntries.next = NULL;
00629 
00630   return E_SUCCESS;
00631 }
00632 #endif
00633 
00640 SINT32 CAFirstMixChannelList::remove(CAMuxSocket* pMuxSocket)
00641   {
00642     if(pMuxSocket==NULL)
00643       return E_UNKNOWN;
00644     SINT32 hashkey=pMuxSocket->getHashKey();
00645     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00646       return E_UNKNOWN;
00647     m_Mutex.lock();
00648     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00649     if(pHashTableEntry->pMuxSocket==NULL) //this connection is not in the list
00650       {
00651         m_Mutex.unlock();
00652         return E_UNKNOWN;
00653       }
00654   #ifdef DELAY_USERS
00655     m_pMutexDelayChannel->lock();
00656     m_pDelayBuckets[pHashTableEntry->delayBucketID]=NULL;
00657     m_pMutexDelayChannel->unlock();
00658   #endif
00659     pHashTableEntry->pControlChannelDispatcher->deleteAllControlChannels();
00660     delete pHashTableEntry->pControlChannelDispatcher; //deletes the dispatcher and all associated control channels
00661     delete pHashTableEntry->pControlMessageQueue;
00662     pHashTableEntry->pControlChannelDispatcher = NULL;
00663     pHashTableEntry->pControlMessageQueue = NULL;
00664     if(m_listHashTableNext==pHashTableEntry) //adjust the enumeration over all connections (@see getNext())
00665       m_listHashTableNext=pHashTableEntry->list_HashEntries.next;
00666 
00667     if(pHashTableEntry->list_HashEntries.prev==NULL) //if entry is the head of the connection list
00668     {
00669       if(pHashTableEntry->list_HashEntries.next==NULL) //if entry is also the last (so the only one in the list..)
00670       {
00671         m_listHashTableHead=NULL; //list is now empty
00672       }
00673       else
00674       {//remove the head of the list
00675         m_listHashTableHead=pHashTableEntry->list_HashEntries.next;
00676         m_listHashTableHead->list_HashEntries.prev=NULL;
00677       }
00678     }
00679     else
00680     { //the connection is not the head of the list
00681       if(pHashTableEntry->list_HashEntries.next==NULL)
00682       {//the connection is the last element in the list
00683         pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=NULL;
00684       }
00685       else
00686       {//its a simple middle element
00687         pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=pHashTableEntry->list_HashEntries.next;
00688         pHashTableEntry->list_HashEntries.next->list_HashEntries.prev=pHashTableEntry->list_HashEntries.prev;
00689       }
00690     }
00691 
00692 
00693 #ifdef PAYMENT
00694     removeFromTimeoutList(pHashTableEntry);
00695 #endif
00696 
00697     fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
00698     fmChannelListEntry* pTmpEntry;
00699     while(pEntry!=NULL)//for all channels....
00700       {
00701         //remove the out channel form the out channel hast table
00702         hashkey=pEntry->channelOut&0x0000FFFF;
00703         pTmpEntry=m_HashTableOutChannels[hashkey];
00704         while(pTmpEntry!=NULL)
00705           {
00706             if(pTmpEntry->channelOut==pEntry->channelOut)
00707               {//we have found the entry
00708                 if(pTmpEntry->list_OutChannelHashTable.prev==NULL) //it's the head
00709                   {
00710                     if(pTmpEntry->list_OutChannelHashTable.next==NULL)
00711                       {//it's also the last Element
00712                         m_HashTableOutChannels[hashkey]=NULL; //empty this hash bucket
00713                       }
00714                     else
00715                       {
00716                         pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=NULL;
00717                         m_HashTableOutChannels[hashkey]=pTmpEntry->list_OutChannelHashTable.next;
00718                       }
00719                   }
00720                 else
00721                   {//not the head
00722                     if(pTmpEntry->list_OutChannelHashTable.next==NULL)
00723                       {//but the last
00724                         pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=NULL;
00725                       }
00726                     else
00727                       {//a middle element
00728                         pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=pTmpEntry->list_OutChannelHashTable.next;
00729                         pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=pTmpEntry->list_OutChannelHashTable.prev;
00730                       }
00731                   }
00732                 break;
00733               }
00734             pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
00735         }
00736 
00737         pTmpEntry=pEntry->list_InChannelPerSocket.next;
00738 #ifndef DO_TRACE
00739         delete pEntry;
00740         pEntry = NULL;
00741 #else
00742         deleteChannelListEntry(pEntry);
00743 #endif
00744         pEntry=pTmpEntry;
00745       }
00746 /* already done by pHashTableEntry->pControlChannelDispatcher->deleteAllControlChannels();
00747 #ifdef PAYMENT
00748     // cleanup accounting information
00749     CAAccountingInstance::cleanupTableEntry(pHashTableEntry);
00750 #endif
00751 */
00752 #ifdef LOG_DIALOG
00753     delete[] pHashTableEntry->strDialog;
00754     pHashTableEntry->strDialog = NULL;
00755 #endif
00756 #ifdef PAYMENT
00757     CAConditionVariable *rescue = pHashTableEntry->cleanupNotifier;
00758 #endif
00759     //TODO: a bit more precise reference cleanup
00760     memset(pHashTableEntry,0,sizeof(fmHashTableEntry)); //'delete' the connection from the connection hash table
00761 
00762 #ifdef PAYMENT
00763     pHashTableEntry->cleanupNotifier = rescue;
00764     pHashTableEntry->cleanupNotifier->lock();
00765     pHashTableEntry->cleanupNotifier->signal();
00766     pHashTableEntry->cleanupNotifier->unlock();
00767 #endif
00768     m_Mutex.unlock();
00769     return E_SUCCESS;
00770   }
00771 
00772 
00773 #ifdef NEW_MIX_TYPE
00774 /* some additional methods for TypeB first mixes */
00775 
00783 SINT32 CAFirstMixChannelList::removeClientPart(CAMuxSocket* pMuxSocket)
00784   {
00785     if(pMuxSocket==NULL)
00786       return E_UNKNOWN;
00787     SINT32 hashkey=pMuxSocket->getSocket();
00788     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00789       return E_UNKNOWN;
00790     m_Mutex.lock();
00791     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00792     if(pHashTableEntry->pMuxSocket==NULL) //this connection is not in the list
00793       {
00794         m_Mutex.unlock();
00795         return E_UNKNOWN;
00796       }
00797     #ifdef DELAY_USERS
00798       m_pMutexDelayChannel->lock();
00799       m_pDelayBuckets[pHashTableEntry->delayBucketID]=NULL;
00800       m_pMutexDelayChannel->unlock();
00801     #endif
00802     pHashTableEntry->pControlChannelDispatcher->deleteAllControlChannels();
00803     delete pHashTableEntry->pControlChannelDispatcher; //deletes the dispatcher and all associated control channels
00804     pHashTableEntry->pControlChannelDispatcher = NULL;
00805     if(m_listHashTableNext==pHashTableEntry) //adjust the enumeration over all connections (@see getNext())
00806       m_listHashTableNext=pHashTableEntry->list_HashEntries.next;
00807 
00808     if(pHashTableEntry->list_HashEntries.prev==NULL) //if entry is the head of the connection list
00809       {
00810         if(pHashTableEntry->list_HashEntries.next==NULL) //if entry is also the last (so the only one in the list..)
00811           {
00812             m_listHashTableHead=NULL; //list is now empty
00813           }
00814         else
00815           {//remove the head of the list
00816             m_listHashTableHead=pHashTableEntry->list_HashEntries.next;
00817             m_listHashTableHead->list_HashEntries.prev=NULL;
00818           }
00819       }
00820     else
00821       {//the connection is not the head of the list
00822         if(pHashTableEntry->list_HashEntries.next==NULL)
00823           {//the connection is the last element in the list
00824             pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=NULL;
00825           }
00826         else
00827           {//its a simple middle element
00828             pHashTableEntry->list_HashEntries.prev->list_HashEntries.next=pHashTableEntry->list_HashEntries.next;
00829             pHashTableEntry->list_HashEntries.next->list_HashEntries.prev=pHashTableEntry->list_HashEntries.prev;
00830           }
00831       }
00832 
00833     removeFromTimeoutList(pHashTableEntry);
00834 
00835 
00836     fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
00837     while(pEntry!=NULL)//for all channels....
00838       {
00839         /* leave a dummy-entry in the out-channels-table until we receive a
00840          * CLOSE-message for the channel from the last mix (else we could
00841          * re-use it, while the last mix is still using the old channel),
00842          * therefore set the the pointer for the in-channel-part to NULL
00843          */
00844         pEntry->pHead = NULL;
00845         pEntry = pEntry->list_InChannelPerSocket.next;
00846       }
00847     #ifdef PAYMENT
00848       // cleanup accounting information
00849       CAAccountingInstance::cleanupTableEntry(pHashTableEntry);
00850     #endif
00851     memset(pHashTableEntry,0,sizeof(fmHashTableEntry)); //'delete' the connection from the connection hash table
00852     m_Mutex.unlock();
00853     return E_SUCCESS;
00854   }
00855 
00861 void CAFirstMixChannelList::removeVacantOutChannel(fmChannelListEntry* pEntry) {
00862   if (pEntry != NULL) {
00863     if (pEntry->pHead == NULL) {
00864       /* must be a vacant channel */
00865       m_Mutex.lock();
00866       fmChannelListEntry* pTmpEntry;
00867       /* check whether the enty is in the out-channel-table */
00868       SINT32 hashkey = pEntry->channelOut & 0x0000FFFF;
00869       pTmpEntry = m_HashTableOutChannels[hashkey];
00870       while (pTmpEntry != NULL) {
00871         if (pTmpEntry->channelOut == pEntry->channelOut) {
00872           //we have found the entry
00873           if (pTmpEntry->list_OutChannelHashTable.prev==NULL) { //it's the head
00874             if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
00875               //it's also the last Element
00876               m_HashTableOutChannels[hashkey] = NULL; //empty this hash bucket
00877             }
00878             else {
00879               pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=NULL;
00880               m_HashTableOutChannels[hashkey]=pTmpEntry->list_OutChannelHashTable.next;
00881             }
00882           }
00883           else {
00884             //not the head
00885             if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
00886               //but the last
00887               pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=NULL;
00888             }
00889             else {
00890               //a middle element
00891               pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=pTmpEntry->list_OutChannelHashTable.next;
00892               pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=pTmpEntry->list_OutChannelHashTable.prev;
00893             }
00894           }
00895           break;
00896         }
00897         pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
00898       }
00899       /* entry is not in the table any more */
00900       #ifndef DO_TRACE
00901         delete pEntry;
00902         pEntry = NULL;
00903       #else
00904         deleteChannelListEntry(pEntry);
00905       #endif
00906       m_Mutex.unlock();
00907     }
00908   }
00909 }
00910 
00915 void CAFirstMixChannelList::cleanVacantOutChannels() {
00916   m_Mutex.lock();
00917   SINT32 hashkey = 0;
00918   do {
00919     fmChannelListEntry* pTmpEntry = m_HashTableOutChannels[hashkey];
00920     while (pTmpEntry != NULL) {
00921       if (pTmpEntry->pHead == NULL) {
00922         /* we have found a vacant channel */
00923         if (pTmpEntry->list_OutChannelHashTable.prev==NULL) { //it's the head
00924           if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
00925             //it's also the last Element
00926             m_HashTableOutChannels[hashkey] = NULL; //empty this hash bucket
00927           }
00928           else {
00929             pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=NULL;
00930             m_HashTableOutChannels[hashkey]=pTmpEntry->list_OutChannelHashTable.next;
00931           }
00932         }
00933         else {
00934           //not the head
00935           if (pTmpEntry->list_OutChannelHashTable.next==NULL) {
00936             //but the last
00937             pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=NULL;
00938           }
00939           else {
00940             //a middle element
00941             pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=pTmpEntry->list_OutChannelHashTable.next;
00942             pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=pTmpEntry->list_OutChannelHashTable.prev;
00943           }
00944         }
00945         /* entry is removed from the table, now delete the channel-cipher */
00946         delete pTmpEntry->pCipher;
00947         pTmpEntry->pCipher = NULL;
00948         fmChannelListEntry* pRemoveEntry = pTmpEntry;
00949         pTmpEntry = pTmpEntry->list_OutChannelHashTable.next;
00950         /* delete the entry */
00951         #ifndef DO_TRACE
00952           delete pRemoveEntry;
00953           pRemoveEntry = NULL;
00954         #else
00955           deleteChannelListEntry(pEntry);
00956         #endif
00957       }
00958       else {
00959         /* not a vacant channel -> try the next channel in the hashtable-line */
00960         pTmpEntry = pTmpEntry->list_OutChannelHashTable.next;
00961       }
00962     }
00963     /* we have processed a whole line of the channel-table -> process the next
00964      * one
00965      */
00966     hashkey = (hashkey + 1) & 0x0000FFFF;
00967   }
00968   while (hashkey != 0);
00969   /* we have processed the whole out-channel-table */
00970   m_Mutex.unlock();
00971 }
00972 #endif //NEW_MIX_TYPE (TypeB first mixes)
00973 
00980 SINT32 CAFirstMixChannelList::removeChannel(CAMuxSocket* pMuxSocket,HCHANNEL channelIn)
00981   {
00982     if(pMuxSocket==NULL)
00983       return E_UNKNOWN;
00984     SINT32 hashkey=pMuxSocket->getHashKey();
00985     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
00986       return E_UNKNOWN;
00987     m_Mutex.lock();
00988     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
00989     if(pHashTableEntry->pMuxSocket==NULL)
00990       {
00991         m_Mutex.unlock();
00992         return E_UNKNOWN;
00993       }
00994     fmChannelListEntry* pEntry=pHashTableEntry->pChannelList;
00995     while(pEntry!=NULL)
00996       {
00997         if(pEntry->channelIn==channelIn) //search for the channel
00998           {
00999             hashkey=pEntry->channelOut&0x0000FFFF; //remove the out channel from the out channel hash table
01000             fmChannelListEntry*pTmpEntry=m_HashTableOutChannels[hashkey];
01001             while(pTmpEntry!=NULL)
01002               {
01003                 if(pTmpEntry->channelOut==pEntry->channelOut)
01004                   {//found it in the out channel hash table
01005                     if(pTmpEntry->list_OutChannelHashTable.prev==NULL) //head
01006                       {
01007                         if(pTmpEntry->list_OutChannelHashTable.next==NULL)
01008                           {
01009                             m_HashTableOutChannels[hashkey]=NULL;
01010                           }
01011                         else
01012                           {
01013 
01014                             pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=NULL;
01015                             m_HashTableOutChannels[hashkey]=pTmpEntry->list_OutChannelHashTable.next;
01016                           }
01017                       }
01018                     else
01019                       {
01020                         if(pTmpEntry->list_OutChannelHashTable.next==NULL)
01021                           {//last element
01022                             pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=NULL;
01023                           }
01024                         else
01025                           {//middle element
01026                             pTmpEntry->list_OutChannelHashTable.prev->list_OutChannelHashTable.next=pTmpEntry->list_OutChannelHashTable.next;
01027                             pTmpEntry->list_OutChannelHashTable.next->list_OutChannelHashTable.prev=pTmpEntry->list_OutChannelHashTable.prev;
01028                           }
01029                       }
01030                     break;
01031                   }
01032                 pTmpEntry=pTmpEntry->list_OutChannelHashTable.next;
01033             }
01034 
01035             //remove the channel from the channel hast table
01036             if(pEntry->list_InChannelPerSocket.prev==NULL) //head
01037               {
01038                 if(pEntry->list_InChannelPerSocket.next==NULL)
01039                   {//the only element
01040                     pHashTableEntry->pChannelList=NULL;
01041                   }
01042                 else
01043                   {
01044                     pEntry->list_InChannelPerSocket.next->list_InChannelPerSocket.prev=NULL;
01045                     pHashTableEntry->pChannelList=pEntry->list_InChannelPerSocket.next;
01046                   }
01047               }
01048             else
01049               {
01050                 if(pEntry->list_InChannelPerSocket.next==NULL)
01051                   {//the last element
01052                     pEntry->list_InChannelPerSocket.prev->list_InChannelPerSocket.next=NULL;
01053                   }
01054                 else
01055                   {//a middle element
01056                     pEntry->list_InChannelPerSocket.prev->list_InChannelPerSocket.next=pEntry->list_InChannelPerSocket.next;
01057                     pEntry->list_InChannelPerSocket.next->list_InChannelPerSocket.prev=pEntry->list_InChannelPerSocket.prev;
01058                   }
01059               }
01060             #ifndef DO_TRACE
01061               delete pEntry;
01062               pEntry = NULL;
01063             #else
01064               deleteChannelListEntry(pEntry);
01065             #endif
01066             pHashTableEntry->cNumberOfChannels--;
01067             m_Mutex.unlock();
01068             return E_SUCCESS;
01069           }
01070         pEntry=pEntry->list_InChannelPerSocket.next; //try next channel
01071       }
01072     m_Mutex.unlock();
01073     return E_UNKNOWN;//not found
01074   }
01075 
01081 fmHashTableEntry* CAFirstMixChannelList::getFirst()
01082   {
01083     m_Mutex.lock();
01084     if(m_listHashTableHead!=NULL)
01085       m_listHashTableNext=m_listHashTableHead->list_HashEntries.next;
01086     else
01087       m_listHashTableNext=NULL;
01088     m_Mutex.unlock();
01089     return m_listHashTableHead;
01090   }
01091 
01097 fmHashTableEntry* CAFirstMixChannelList::getNext()
01098   {
01099     m_Mutex.lock();
01100     fmHashTableEntry* tmpEntry=m_listHashTableNext;
01101     if(m_listHashTableNext!=NULL)
01102       m_listHashTableNext=m_listHashTableNext->list_HashEntries.next;
01103     m_Mutex.unlock();
01104     return tmpEntry;
01105   }
01106 
01113 fmChannelListEntry* CAFirstMixChannelList::getFirstChannelForSocket(CAMuxSocket* pMuxSocket)
01114   {
01115     if(pMuxSocket==NULL)
01116       return NULL;
01117     SINT32 hashkey=pMuxSocket->getHashKey();
01118     if(hashkey>MAX_HASH_KEY-1||hashkey<0)
01119       return NULL;
01120     fmHashTableEntry* pHashTableEntry=m_HashTable[hashkey];
01121     return pHashTableEntry->pChannelList;
01122   }
01123 
01130 fmChannelListEntry* CAFirstMixChannelList::getNextChannel(fmChannelListEntry* pEntry)
01131   {
01132     if(pEntry==NULL)
01133       return NULL;
01134     return pEntry->list_InChannelPerSocket.next;
01135   }
01136 
01137 SINT32 CAFirstMixChannelList::test()
01138   {
01139     CAFirstMixChannelList* pList=new CAFirstMixChannelList();
01140     CAMuxSocket *pMuxSocket=new CAMuxSocket();
01141     pMuxSocket->getCASocket()->create();
01142     UINT8 peerIP[4];
01143 #ifndef LOG_DIALOG
01144     pList->add(pMuxSocket,peerIP,NULL,NULL,NULL);
01145 #else
01146     pList->add(pMuxSocket,peerIP,NULL,(UINT8*)"1");
01147 #endif
01148 #if defined(HAVE_CRTDBG)
01149     _CrtMemState s1, s2, s3;
01150     _CrtMemCheckpoint( &s1 );
01151 #endif
01152     UINT32 /*channelIn,*/i,channelOut;
01153     for(i=0;i<50;i++)
01154       pList->addChannel(pMuxSocket,i,NULL,&channelOut);
01155     for(i=0;i<50;i++)
01156       pList->removeChannel(pMuxSocket,i);
01157 #if defined(HAVE_CRTDBG)
01158     _CrtMemCheckpoint( &s2 );
01159     if ( _CrtMemDifference( &s3, &s1, &s2 ) )
01160       _CrtMemDumpStatistics( &s3 );
01161 #endif
01162 
01163     pList->remove(pMuxSocket);
01164     delete pMuxSocket;
01165     pMuxSocket = NULL;
01166     delete pList;
01167     pList = NULL;
01168     return E_SUCCESS;
01169   }
01170 
01171 #ifdef DELAY_USERS
01172   THREAD_RETURN fml_loopDelayBuckets(void* param)
01173     {
01174       INIT_STACK;
01175       BEGIN_STACK("CAFirstMixChannelList::fml_loopDelayBuckets");
01176 
01177       CAFirstMixChannelList* pChannelList=(CAFirstMixChannelList*)param;
01178       volatile UINT32** pDelayBuckets=pChannelList->m_pDelayBuckets;
01179       while(pChannelList->m_bDelayBucketsLoopRun)
01180         {
01181           pChannelList->m_pMutexDelayChannel->lock();
01182           UINT32 u32BucketGrow=pChannelList->m_u32DelayChannelBucketGrow;
01183           UINT32 u32MaxBucket=u32BucketGrow*10;
01184           for(UINT32 i=0;i<MAX_POLLFD;i++)
01185             {
01186               if(pDelayBuckets[i]!=NULL&&*(pDelayBuckets[i])<u32MaxBucket)
01187               {
01188                 *(pDelayBuckets[i])+=u32BucketGrow;
01189               }
01190             }
01191           pChannelList->m_pMutexDelayChannel->unlock();
01192           msSleep(pChannelList->m_u32DelayChannelBucketGrowIntervall);
01193         }
01194 
01195       FINISH_STACK("CAFirstMixChannelList::fml_loopDelayBuckets");
01196 
01197       THREAD_RETURN_SUCCESS;
01198     }
01199 
01200   void CAFirstMixChannelList::decDelayBuckets(UINT32 delayBucketID)
01201   {
01202     m_pMutexDelayChannel->lock();
01203     if(delayBucketID < MAX_POLLFD)
01204     {
01205       if(m_pDelayBuckets[delayBucketID] != NULL)
01206       {
01207         *(m_pDelayBuckets[delayBucketID]) -= ( (*(m_pDelayBuckets[delayBucketID])) > 0 ) ? 1 : 0;
01208       }
01209       /*CAMsg::printMsg(LOG_DEBUG,"DelayBuckets decrementing ID %u downto %u\n",
01210                 delayBucketID, (*(m_pDelayBuckets[delayBucketID])) );*/
01211     }
01212     m_pMutexDelayChannel->unlock();
01213   }
01214 
01215   bool CAFirstMixChannelList::hasDelayBuckets(UINT32 delayBucketID)
01216   {
01217     bool ret = false;
01218     m_pMutexDelayChannel->lock();
01219     if(delayBucketID < MAX_POLLFD)
01220     {
01221       if(m_pDelayBuckets[delayBucketID] != NULL)
01222       {
01223         ret = ( (*(m_pDelayBuckets[delayBucketID])) > 0 );
01224       }
01225     }
01226     m_pMutexDelayChannel->unlock();
01227     return ret;
01228   }
01229 
01230   void CAFirstMixChannelList::setDelayParameters(UINT32 unlimitTraffic,UINT32 bucketGrow,UINT32 intervall)
01231     {
01232       m_pMutexDelayChannel->lock();
01233       CAMsg::printMsg(LOG_DEBUG,"CAFirstMixChannelList - Set new traffic limit per user- unlimit: %u bucketgrow: %u intervall %u\n",
01234         unlimitTraffic,bucketGrow,intervall);
01235       m_u32DelayChannelUnlimitTraffic=unlimitTraffic;
01236       m_u32DelayChannelBucketGrow=bucketGrow;
01237       m_u32DelayChannelBucketGrowIntervall=intervall;
01238       for(UINT32 i=0;i<MAX_POLLFD;i++)
01239         if(m_pDelayBuckets[i]!=NULL)
01240           *(m_pDelayBuckets[i])=m_u32DelayChannelUnlimitTraffic;
01241       m_pMutexDelayChannel->unlock();
01242     }
01243 
01244 #endif
01245 #endif //ONLY_LOCAL_PROXY