CAChainTable.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006, The JAP-Team 
00003  * All rights reserved.
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, 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
00011  *     notice, this list of conditions and the following disclaimer in the
00012  *     documentation and/or other materials provided with the distribution.
00013  *
00014  *   - Neither the name of the University of Technology Dresden, Germany nor
00015  *     the names of its contributors may be used to endorse or promote
00016  *     products derived from this software without specific prior written
00017  *     permission. 
00018  *
00019  *  
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00023  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
00024  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030  * POSSIBILITY OF SUCH DAMAGE
00031  */
00032 #include "../StdAfx.h"
00033 #ifndef ONLY_LOCAL_PROXY
00034 #include "CAChainTable.hpp"
00035 #include "typedefsb.hpp"
00036 #include "../CAUtil.hpp"
00037 
00038 
00039 CAChainTable::CAChainTable(void) {
00040   m_pChainTable = new (t_chaintableEntry*[0x10000]);
00041   for (UINT32 i = 0; i < 0x10000; i++) {
00042     m_pChainTable[i] = NULL;
00043   }
00044   m_pMutex = new CAMutex();
00045   m_chaintableSize = 0;
00046   m_pChaintableIterator = NULL;
00047   #ifdef DELAY_CHANNELS
00048     m_initialBucketSize = DELAY_CHANNEL_TRAFFIC;
00049     m_delayBucketGrow = DELAY_BUCKET_GROW;
00050     m_delayBucketGrowInterval = DELAY_BUCKET_GROW_INTERVALL;
00051     m_pDelayBucketMutex = new CAMutex();
00052     m_pDelayBuckets = new SINT32[MAX_POLLFD];
00053     for (UINT32 i = 0; i < MAX_POLLFD; i++) {
00054       m_pDelayBuckets[i] = -1;
00055     }
00056     /* start the delay-buckets-refill loop */
00057     m_delayBucketsLoopRun = true;
00058     m_pDelayBucketsLoop = new CAThread((UINT8*)"CAChainTable: delay-buckets refill thread");
00059     m_pDelayBucketsLoop->setMainLoop(lml_chaintableDelayBucketsLoop);
00060     m_pDelayBucketsLoop->start(this);
00061   #endif
00062 }
00063 
00064 CAChainTable::~CAChainTable(void) {
00065   /* use the iterator to clean the table */
00066   getFirstEntry();
00067   while (m_pChaintableIterator != NULL) {
00068     /* chaintable iterator is removed, if last entry is reached */
00069     m_pChaintableIterator->removeEntry = true;
00070     /* entry is removed automatically, when the iterator points to the next
00071      * entry
00072      */
00073     getNextEntry();
00074   }
00075   #ifdef DELAY_CHANNELS
00076     m_delayBucketsLoopRun = false;
00077     /* wait for the delay-buckets-refill loop */
00078     m_pDelayBucketsLoop->join();
00079     delete m_pDelayBucketsLoop;
00080     m_pDelayBucketsLoop = NULL;
00081     delete m_pDelayBucketMutex;
00082     m_pDelayBucketMutex = NULL;
00083     delete []m_pDelayBuckets;
00084     m_pDelayBuckets = NULL;
00085   #endif
00086   delete m_pMutex;
00087   m_pMutex = NULL;
00088   delete []m_pChainTable;
00089   m_pChainTable = NULL;
00090 }
00091 
00092 CAChain* CAChainTable::getEntry(UINT8* a_chainId) {
00093   m_pMutex->lock();
00094   CAChain* returnedChain = NULL;
00095   t_chaintableEntry* chaintableEntry = getEntryInternal(a_chainId);
00096   if (chaintableEntry != NULL) {
00097     returnedChain = chaintableEntry->chain;
00098   }
00099   m_pMutex->unlock();
00100   return returnedChain;
00101 }
00102 
00103 void CAChainTable::deleteEntry(UINT8* a_chainId) {
00104   m_pMutex->lock();
00105   t_chaintableEntry* chaintableEntry = getEntryInternal(a_chainId);
00106   if (chaintableEntry != NULL) {
00107     /* we have found an entry with the specified ID -> check whether the
00108      * iterator points to it
00109      */
00110     if (m_pChaintableIterator != NULL) {
00111       if (m_pChaintableIterator->currentEntry == chaintableEntry) {
00112         /* don't remove the entry but set the remove-flag for the iterator */
00113         m_pChaintableIterator->removeEntry = true;
00114       }
00115       else {
00116         removeEntryInternal(chaintableEntry);
00117       }
00118     }
00119     else {
00120       removeEntryInternal(chaintableEntry);
00121     }
00122   }
00123   m_pMutex->unlock();
00124 }
00125 
00126 CAChain* CAChainTable::getFirstEntry() {
00127   CAChain* firstChain = NULL;
00128   m_pMutex->lock();
00129   if (m_pChaintableIterator == NULL) {
00130     m_pChaintableIterator = new t_chaintableIterator;
00131   }
00132   else {
00133     /* look whether we shall remove our last entry */
00134     if (m_pChaintableIterator->removeEntry) {
00135       removeEntryInternal(m_pChaintableIterator->currentEntry);
00136     }
00137   }
00138   m_pChaintableIterator->nextHashkey = 0;
00139   m_pChaintableIterator->removeEntry = false;
00140   m_pChaintableIterator->currentEntry = NULL;
00141   getNextEntryInternal(m_pChaintableIterator);
00142   if (m_pChaintableIterator->currentEntry == NULL) {
00143     /* no entries in the table */
00144     delete m_pChaintableIterator;
00145     m_pChaintableIterator = NULL;
00146   }
00147   else {
00148     firstChain = m_pChaintableIterator->currentEntry->chain;
00149   }
00150   m_pMutex->unlock();
00151   return firstChain;
00152 }
00153 
00154 CAChain* CAChainTable::getNextEntry() {
00155   CAChain* nextChain = NULL;
00156   m_pMutex->lock();
00157   if (m_pChaintableIterator != NULL) {
00158     getNextEntryInternal(m_pChaintableIterator);
00159     if (m_pChaintableIterator->currentEntry == NULL) {
00160       /* no more entries in the table */
00161       delete m_pChaintableIterator;
00162       m_pChaintableIterator = NULL;
00163     }
00164     else {
00165       nextChain = m_pChaintableIterator->currentEntry->chain;
00166     }
00167   }
00168   m_pMutex->unlock();
00169   return nextChain;
00170 }
00171 
00172 CAChain* CAChainTable::createEntry() {
00173   m_pMutex->lock();
00174   if (m_chaintableSize >= MAX_POLLFD) {
00175     /* we cannot create more chains because we are not able to handle more
00176      * sockets
00177      */
00178     m_pMutex->unlock();
00179     return NULL;
00180   }
00181   /* create a unique chain-id */
00182   UINT8* chainId = new UINT8[CHAIN_ID_LENGTH];
00183   do {
00184     if (getRandom(chainId, CHAIN_ID_LENGTH) != E_SUCCESS) {
00185       m_pMutex->unlock();
00186       delete []chainId;
00187       chainId = NULL;
00188       return NULL;
00189     }
00190   }
00191   while (getEntryInternal(chainId) != NULL);
00192   t_chaintableEntry* newEntry = new t_chaintableEntry;
00193   #ifndef DELAY_CHANNELS
00194     newEntry->chain = new CAChain(chainId);
00195   #else
00196     /* find an unused delay-bucket */
00197     m_pDelayBucketMutex->lock();
00198     UINT32 i = 0;
00199     bool bucketFound = false;
00200     while ((!bucketFound) && (i < MAX_POLLFD)) {
00201       if (m_pDelayBuckets[i] == -1) {
00202         bucketFound = true;
00203       }
00204       else {
00205         i++;
00206       }
00207     }
00208     if (!bucketFound) {
00209       /* we found no bucket -> this shouldn't happen because there cannot be
00210        * more chains than buckets
00211        */
00212       m_pDelayBucketMutex->unlock();
00213       delete newEntry;
00214       newEntry = NULL;
00215       delete []chainId;
00216       chainId = NULL;
00217       m_pMutex->unlock();
00218       return NULL;
00219     }
00220     /* initalize our bucket */
00221     m_pDelayBuckets[i] = (SINT32)m_initialBucketSize;
00222     m_pDelayBucketMutex->unlock();
00223     newEntry->chain = new CAChain(chainId, m_pDelayBucketMutex, &(m_pDelayBuckets[i]));
00224   #endif
00225   /* take the lower 16 bits as key for the hashtable */
00226   UINT16 hashKey = (((UINT16)(chainId[CHAIN_ID_LENGTH - 2])) << 8) | (UINT16)(chainId[CHAIN_ID_LENGTH - 1]);
00227   /* now add the entry at the begin of the hashtable-line */
00228   newEntry->rightEntry = m_pChainTable[hashKey];
00229   newEntry->rightEntryPointerOfLeftEntry = &(m_pChainTable[hashKey]);
00230   m_pChainTable[hashKey] = newEntry;
00231   if (newEntry->rightEntry != NULL) {
00232     newEntry->rightEntry->rightEntryPointerOfLeftEntry = &(newEntry->rightEntry);
00233   }
00234   m_chaintableSize++;
00235   m_pMutex->unlock();
00236   return (newEntry->chain);
00237 }
00238 
00239 UINT32 CAChainTable::getSize() {
00240   UINT32 chaintableSize;
00241   m_pMutex->lock();
00242   chaintableSize = m_chaintableSize;
00243   m_pMutex->unlock();
00244   return chaintableSize;
00245 }
00246 
00247 
00248 t_chaintableEntry* CAChainTable::getEntryInternal(UINT8* a_chainId) {
00249   /* mutex must be already locked */
00250   /* take the lower 16 bits as key for the hashtable */
00251   UINT16 hashKey = (((UINT16)(a_chainId[CHAIN_ID_LENGTH - 2])) << 8) | (UINT16)(a_chainId[CHAIN_ID_LENGTH - 1]);
00252   bool entryFound = false;
00253   t_chaintableEntry* currentEntry = m_pChainTable[hashKey];
00254   while ((currentEntry != NULL) && !entryFound) {
00255     /* a removed entry could be in the table, if the iterator points to it ->
00256      * we have to check it
00257      */
00258     bool entryVirtualRemoved = false;
00259     if (m_pChaintableIterator != NULL) {
00260       if ((m_pChaintableIterator->currentEntry == currentEntry) && (m_pChaintableIterator->removeEntry)) {
00261         entryVirtualRemoved = true;
00262         /* skip this entry */
00263         currentEntry = currentEntry->rightEntry;
00264       }
00265     }
00266     if (!entryVirtualRemoved) {
00267       /* compare the Chain-IDs (lower 2 bytes are identical because of the same
00268        * hashkey -> don't compare them)
00269        */
00270       if (memcmp(currentEntry->chain->getChainId(), a_chainId, CHAIN_ID_LENGTH - 2) == 0) {
00271         /* we have found the entry */
00272         entryFound = true;
00273       }
00274       else {
00275         currentEntry = currentEntry->rightEntry;
00276       }
00277     }
00278   }
00279   return currentEntry;
00280 }
00281 
00282 void CAChainTable::removeEntryInternal(t_chaintableEntry* a_entry) {
00283   /* mutex must be already locked */
00284   *(a_entry->rightEntryPointerOfLeftEntry) = a_entry->rightEntry;
00285   if (a_entry->rightEntry != NULL) {
00286     a_entry->rightEntry->rightEntryPointerOfLeftEntry = a_entry->rightEntryPointerOfLeftEntry;
00287   }
00288   /* delete the chain */
00289   delete a_entry->chain;
00290   a_entry->chain = NULL;
00291   /* delete the table-entry */
00292   delete a_entry;
00293   a_entry = NULL;
00294   m_chaintableSize--;
00295 }
00296 
00297 void CAChainTable::getNextEntryInternal(t_chaintableIterator* a_iterator) {
00298   /* mutex must be already locked */
00299   t_chaintableEntry* nextEntry;
00300   if (a_iterator->currentEntry == NULL) {
00301     nextEntry = NULL;
00302   }
00303   else {
00304     nextEntry = a_iterator->currentEntry->rightEntry;
00305     /* look whether we shall remove our last entry */
00306     if (a_iterator->removeEntry) {
00307       removeEntryInternal(a_iterator->currentEntry);
00308       a_iterator->removeEntry = false;
00309     }
00310   }
00311   if (nextEntry == NULL) {
00312     /* we have to start at the current hashtable-line until we find a
00313      * hashtable-line with entries or reach again the top of the table
00314      */
00315     do {
00316       a_iterator->currentEntry = m_pChainTable[a_iterator->nextHashkey];
00317       (a_iterator->nextHashkey)++;
00318     }
00319     while ((a_iterator->currentEntry == NULL) && (a_iterator->nextHashkey != 0));
00320     if (a_iterator->nextHashkey == 0) {
00321       /* we have reached the top of the table again */
00322       a_iterator->currentEntry = NULL;
00323     }
00324   }
00325   else {
00326     /* we have another entry in the same hashtable-line */
00327     a_iterator->currentEntry = nextEntry;
00328   }
00329 }
00330 
00331 #ifdef DELAY_CHANNELS
00332   THREAD_RETURN lml_chaintableDelayBucketsLoop(void* a_param) {
00333     /* get the chaintable we are running on from the parameter */
00334     CAChainTable* pChainTable = (CAChainTable*)a_param;
00335     while (pChainTable->m_delayBucketsLoopRun) {
00336       pChainTable->m_pDelayBucketMutex->lock();
00337       SINT32 bucketGrow = (SINT32)(pChainTable->m_delayBucketGrow);
00338       for (UINT32 i = 0; i < MAX_POLLFD; i++) {
00339         if ((pChainTable->m_pDelayBuckets[i]) != -1) {
00340           /* let only grow used buckets, but don't make them too large */
00341           pChainTable->m_pDelayBuckets[i] = min((pChainTable->m_pDelayBuckets[i]) + bucketGrow, MAX_DELAY_BUCKET_SIZE);
00342         }
00343       }
00344       pChainTable->m_pDelayBucketMutex->unlock();
00345       /* sleep some time before the next grow-round starts */
00346       msSleep((UINT16)(pChainTable->m_delayBucketGrowInterval));
00347     }
00348     THREAD_RETURN_SUCCESS;
00349   }
00350 
00351   void CAChainTable::setDelayParameters(UINT32 a_initialBucketSize, UINT32 a_delayBucketGrow, UINT32 a_delayBucketGrowInterval) {
00352     CAMsg::printMsg(LOG_DEBUG, "CAChainTable - Set new traffic limit per channel: inital size: %u bucket grow: %u interval: %u\n", a_initialBucketSize, a_delayBucketGrow, a_delayBucketGrowInterval);
00353     m_pDelayBucketMutex->lock();
00354     m_initialBucketSize = a_initialBucketSize;
00355     m_delayBucketGrow = a_delayBucketGrow;
00356     m_delayBucketGrowInterval = a_delayBucketGrowInterval;
00357     /* re-initialize all used buckets */
00358     for (UINT32 i = 0; i < MAX_POLLFD; i++) {
00359       if (m_pDelayBuckets[i] != -1) {
00360         /* re-initialize only used buckets */
00361         m_pDelayBuckets[i] = a_initialBucketSize;
00362       }
00363     }
00364     m_pDelayBucketMutex->unlock();    
00365   }                                                        
00366 #endif //DELAY_CHANNELS
00367 #endif//onlyLOCAL_PROXY

Generated on Mon Feb 21 23:19:12 2011 for Mixe for Privacy and Anonymity in the Internet by  doxygen 1.5.6