|
Mixe for Privacy and Anonymity in the Internet
|
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 "CALastMixB.hpp" 00035 #include "typedefsb.hpp" 00036 #include "CALastMixBChannelList.hpp" 00037 #include "../CASingleSocketGroup.hpp" 00038 #include "../CAPool.hpp" 00039 #include "../CACmdLnOptions.hpp" 00040 #include "../CAUtil.hpp" 00041 00042 #ifdef HAVE_EPOLL 00043 #include "../CASocketGroupEpoll.hpp" 00044 #endif 00045 00046 CALastMixB::CALastMixB() { 00047 m_pChainTable = NULL; 00048 m_pChannelTable = NULL; 00049 } 00050 00051 void CALastMixB::reconfigureMix() { 00052 #ifdef DELAY_CHANNELS 00053 CAMsg::printMsg(LOG_DEBUG, "CALastMixB: Set new resources limitation parameters.\n"); 00054 if (m_pChainTable != NULL) { 00055 m_pChainTable->setDelayParameters(pglobalOptions->getDelayChannelUnlimitTraffic(), pglobalOptions->getDelayChannelBucketGrow(), pglobalOptions->getDelayChannelBucketGrowIntervall()); 00056 } 00057 #endif 00058 } 00059 00060 00061 SINT32 CALastMixB::loop() { 00062 #ifdef NEW_MIX_TYPE 00063 /* should only be compiled, if TypeB mixes are used */ 00064 m_pChainTable = new CAChainTable(); 00065 m_pChannelTable = new CALastMixBChannelList(); 00066 #ifdef DELAY_CHANNELS 00067 m_pChainTable->setDelayParameters(pglobalOptions->getDelayChannelUnlimitTraffic(), pglobalOptions->getDelayChannelBucketGrow(), pglobalOptions->getDelayChannelBucketGrowIntervall()); 00068 #endif 00069 00070 #ifdef HAVE_EPOLL 00071 CASocketGroupEpoll* psocketgroupCacheRead = new CASocketGroupEpoll(false); 00072 CASocketGroupEpoll* psocketgroupCacheWrite = new CASocketGroupEpoll(true); 00073 #else 00074 CASocketGroup* psocketgroupCacheRead = new CASocketGroup(false); 00075 CASocketGroup* psocketgroupCacheWrite = new CASocketGroup(true); 00076 #endif 00077 00078 UINT8 rsaOutputBuffer[RSA_SIZE]; 00079 m_logUploadedPackets = 0; 00080 m_logDownloadedPackets = 0; 00081 set64((UINT64&)m_logUploadedBytes,(UINT32)0); 00082 set64((UINT64&)m_logDownloadedBytes,(UINT32)0); 00083 00084 /* start logging */ 00085 CAThread* pLogThread = new CAThread((UINT8*)"CALastMixB - LogLoop"); 00086 pLogThread->setMainLoop(lm_loopLog); 00087 pLogThread->start(this); 00088 00089 /* initialize some pointers */ 00090 tQueueEntry* currentQueueEntry = new tQueueEntry; 00091 MIXPACKET* currentMixPacket = &(currentQueueEntry->packet); 00092 t_upstreamChainCell* pChainCell = (t_upstreamChainCell*)(currentMixPacket->data); 00093 00094 #ifdef LOG_CHAIN_STATISTICS 00095 CAMsg::printMsg(LOG_DEBUG, "Chain log format is: Chain-ID, Chain duration [micros], Upload (bytes), Download (bytes), Packets from user, Packets to user\n"); 00096 #endif 00097 00098 while(!m_bRestart) { 00099 /* begin of the mix-loop */ 00100 bool bAktiv = false; 00101 00102 // Step 1a: reading from previous Mix --> now in separate thread 00103 // Step 1b: processing MixPackets from previous mix 00104 00105 if (m_pQueueReadFromMix->getSize() >= sizeof(tQueueEntry)) { 00106 /* there is something to do in upstream-direction */ 00107 bAktiv = true; 00108 UINT32 chains = m_pChainTable->getSize(); 00109 /* limit the number of processed upstream-packets depending on the 00110 * number of currently forwarded data-chains 00111 */ 00112 for (UINT32 k = 0; (k < (chains + 1)) && (m_pQueueReadFromMix->getSize() >= sizeof(tQueueEntry)); k++) { 00113 UINT32 readBytes = sizeof(tQueueEntry); 00114 m_pQueueReadFromMix->get((UINT8*)currentQueueEntry, &readBytes); 00115 #ifdef LOG_PACKET_TIMES 00116 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_start_OP); 00117 #endif 00118 if ((currentMixPacket->channel > 0) && (currentMixPacket->channel < 256)) { 00119 /* it's a control-channel packet */ 00120 m_pMuxInControlChannelDispatcher->proccessMixPacket(currentMixPacket); 00121 /* process the next packet */ 00122 continue; 00123 } 00124 /* a data-channel packet received */ 00125 m_logUploadedPackets++; 00126 if (currentMixPacket->flags & CHANNEL_DUMMY) { 00127 /* it's only a dummy-packet -> ignore it */ 00128 continue; 00129 } 00130 t_lastMixBChannelListEntry* pChannelListEntry = m_pChannelTable->get(currentMixPacket->channel); 00131 if (pChannelListEntry == NULL) { 00132 /* it's a new channel */ 00133 #ifdef _DEBUG1 00134 CAMsg::printMsg(LOG_DEBUG, "New channel from previous Mix!\n"); 00135 #endif 00136 m_pRSA->decrypt(currentMixPacket->data, rsaOutputBuffer); 00137 #ifdef REPLAY_DETECTION 00138 if (m_pReplayDB->insert(rsaOutputBuffer) != E_SUCCESS) { 00139 /* we know such a packet already */ 00140 CAMsg::printMsg(LOG_INFO, "Replay: Duplicate packet ignored.\n"); 00141 /* currently we have to send at least a CHANNEL-CLOSE -> reuse 00142 * our buffers for the response 00143 */ 00144 getRandom(currentMixPacket->data, DATA_SIZE); 00145 currentMixPacket->flags = CHANNEL_CLOSE; 00146 #ifdef LOG_PACKET_TIMES 00147 /* set invalid packet time for the response */ 00148 setZero64(currentQueueEntry->timestamp_proccessing_start); 00149 #endif 00150 m_pQueueSendToMix->add(currentMixPacket, sizeof(tQueueEntry)); 00151 m_logDownloadedPackets++; 00152 /* process the next packet */ 00153 continue; 00154 } 00155 #endif 00156 /* copy the RSA output-buffer back in the mix-packet (without the 00157 * symmetric key -> decrypted data will start at the data-pointer 00158 * of the packet) 00159 */ 00160 memcpy(currentMixPacket->data, rsaOutputBuffer + KEY_SIZE, RSA_SIZE - KEY_SIZE); 00161 /* initialize the channel-cipher */ 00162 CASymCipher* channelCipher = new CASymCipher(); 00163 channelCipher->setKey(rsaOutputBuffer); 00164 /* uncrypt the packet (because the symmetric key at the begin is 00165 * removed, we have to pull out the decrypted data) 00166 */ 00167 channelCipher->crypt1((currentMixPacket->data) + RSA_SIZE, (currentMixPacket->data) + RSA_SIZE - KEY_SIZE, DATA_SIZE - RSA_SIZE); 00168 #ifdef LOG_PACKET_TIMES 00169 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_end_OP); 00170 #endif 00171 UINT16 lengthAndFlags = ntohs(pChainCell->lengthAndFlags); 00172 UINT16 payloadLength = lengthAndFlags & CHAINFLAG_LENGTH_MASK; 00173 if (lengthAndFlags & CHAINFLAG_NEW_CHAIN) { 00174 #ifdef _DEBUG1 00175 CAMsg::printMsg(LOG_DEBUG, "Creating new chain.\n"); 00176 #endif 00177 CAChain* currentChain = m_pChainTable->createEntry(); 00178 if (currentChain == NULL) { 00179 /* we are unable to create a new chain (maximum number of 00180 * chains - defined in MAX_POLLFD - is reached) 00181 */ 00182 CAMsg::printMsg(LOG_INFO, "Unable to create more than %u chains - dropped new chain.\n", MAX_POLLFD); 00183 delete channelCipher; 00184 channelCipher = NULL; 00185 /* currently we have to send at least a CHANNEL-CLOSE -> reuse 00186 * our buffers for the response 00187 */ 00188 getRandom(currentMixPacket->data, DATA_SIZE); 00189 currentMixPacket->flags = CHANNEL_CLOSE; 00190 #ifdef LOG_PACKET_TIMES 00191 /* set invalid packet time for the response */ 00192 setZero64(pQueueEntry->timestamp_proccessing_start); 00193 #endif 00194 m_pQueueSendToMix->add(currentMixPacket, sizeof(tQueueEntry)); 00195 m_logDownloadedPackets++; 00196 /* process the next packet */ 00197 continue; 00198 } 00199 currentChain->addChannel(m_pChannelTable->add(currentMixPacket->channel, channelCipher, currentChain), ((lengthAndFlags & CHAINFLAG_FAST_RESPONSE) == CHAINFLAG_FAST_RESPONSE)); 00200 /* Attention: The type-field is handled as part of the payload- 00201 * data --> to get the useable payload we have to 00202 * subtract the size of the type-field. 00203 */ 00204 payloadLength = payloadLength - 1; 00205 if (payloadLength <= MAX_FIRST_UPSTREAM_CHAINCELL_PAYLOAD) { 00206 /* it's a valid new chain */ 00207 CASocket* tmpSocket = new CASocket; 00208 CACacheLoadBalancing* pLoadBalancing = m_pCacheLB; 00209 if (pChainCell->firstCell.type == MIX_PAYLOAD_SOCKS) { 00210 pLoadBalancing = m_pSocksLB; 00211 } 00212 SINT32 errorCode = E_UNKNOWN; 00213 /* build a new connection to one of the known proxy-servers */ 00214 for (UINT32 count=0; count < pLoadBalancing->getElementCount(); count++) { 00215 tmpSocket->create(); 00216 tmpSocket->setRecvBuff(50000); 00217 tmpSocket->setSendBuff(5000); 00218 errorCode = tmpSocket->connect(*pLoadBalancing->get(), LAST_MIX_TO_PROXY_CONNECT_TIMEOUT); 00219 if (errorCode == E_SUCCESS) { 00220 break; 00221 } 00222 tmpSocket->close(); 00223 } 00224 if (errorCode != E_SUCCESS) { 00225 /* could not connect to any proxy */ 00226 CAMsg::printMsg(LOG_DEBUG,"Cannot connect to Squid!\n"); 00227 delete tmpSocket; 00228 tmpSocket = NULL; 00229 /* close the chain immediately */ 00230 currentChain->signalConnectionError(); 00231 } 00232 else { 00233 /* we have a connection to a proxy */ 00234 #ifdef LOG_CHAIN_STATISTICS 00235 currentChain->setSocket(tmpSocket, 1, payloadLength); 00236 #else 00237 currentChain->setSocket(tmpSocket); 00238 #endif 00239 #ifdef _DEBUG1 00240 /* log the first 30 byte of the chain-data */ 00241 UINT8 c = pChainCell->firstCell.data[30]; 00242 /* make a temporary string-cut after 30 byte */ 00243 pChainCell->firstCell.data[30] = 0; 00244 CAMsg::printMsg(LOG_DEBUG, "Try sending data to Squid: %s\n", pChainCell->firstCell.data); 00245 pChainCell->firstCell.data[30] = c; 00246 #endif 00247 #ifdef LOG_CRIME 00248 if (checkCrime(pChainCell->firstCell.data, payloadLength)) { 00249 /* we've captured a stupid gangsta, who sent a suspected 00250 * webaddress completely in the first packet 00251 */ 00252 UINT8 crimeBuff[MAX_FIRST_UPSTREAM_CHAINCELL_PAYLOAD + 1]; 00253 /* ensure that there is a trailing 0 -> use one byte more 00254 * than necessary for the plain data 00255 */ 00256 memset(crimeBuff, 0, MAX_FIRST_UPSTREAM_CHAINCELL_PAYLOAD + 1); 00257 memcpy(crimeBuff, pChainCell->firstCell.data, payloadLength); 00258 /* for compatibility with the default mix-implementation 00259 * we will send an extra-packet on the channel with a 00260 * crime-signal (without using the channel-cipher) 00261 */ 00262 tQueueEntry oSigCrimeQueueEntry; 00263 memset(&oSigCrimeQueueEntry, 0, sizeof(tQueueEntry)); 00264 UINT32 id = m_pMuxIn->sigCrime(currentMixPacket->channel, &oSigCrimeQueueEntry.packet); 00265 m_pQueueSendToMix->add(&oSigCrimeQueueEntry, sizeof(tQueueEntry)); 00266 m_logDownloadedPackets++; 00267 int log = LOG_ENCRYPTED; 00268 if (!pglobalOptions->isEncryptedLogEnabled()) { 00269 log = LOG_CRIT; 00270 CAMsg::printMsg(log,"Crime detected -- ID: %u -- Content: \n%s\n", id, crimeBuff); 00271 } 00272 } 00273 #endif 00274 if (tmpSocket->sendTimeOut(pChainCell->firstCell.data, payloadLength, LAST_MIX_TO_PROXY_SEND_TIMEOUT) == SOCKET_ERROR) { 00275 #ifdef _DEBUG 00276 CAMsg::printMsg(LOG_DEBUG,"Error sending data to Squid!\n"); 00277 #endif 00278 currentChain->signalConnectionError(); 00279 } 00280 else { 00281 tmpSocket->setNonBlocking(true); 00282 currentChain->addToSocketGroup(psocketgroupCacheRead); 00283 #ifdef LOG_PACKET_TIMES 00284 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_end); 00285 m_pLogPacketStats->addToTimeingStats(*currentQueueEntry, CHANNEL_OPEN, true); 00286 #endif 00287 if (lengthAndFlags & CHAINFLAG_STREAM_CLOSED) { 00288 /* close upstream (after sending data) */ 00289 currentChain->closeUpstream(); 00290 } 00291 } 00292 } 00293 } 00294 else { 00295 /* invalid packet length */ 00296 currentChain->signalConnectionError(); 00297 } 00298 } 00299 else { 00300 /* new-chain flag is not set */ 00301 CAChain* currentChain = m_pChainTable->getEntry(pChainCell->sequelCell.chainId); 00302 if (currentChain != NULL) { 00303 #ifdef _DEBUG1 00304 CAMsg::printMsg(LOG_DEBUG, "Continue existent chain.\n"); 00305 #endif 00306 /* we've found the specified chain in the table */ 00307 currentChain->addChannel(m_pChannelTable->add(currentMixPacket->channel, channelCipher, currentChain), ((lengthAndFlags & CHAINFLAG_FAST_RESPONSE) == CHAINFLAG_FAST_RESPONSE)); 00308 if (payloadLength <= MAX_SEQUEL_UPSTREAM_CHAINCELL_PAYLOAD) { 00309 /* payload-length is valid */ 00310 if (payloadLength > 0) { 00311 currentChain->addDataToUpstreamQueue(pChainCell->sequelCell.data, payloadLength); 00312 currentChain->addToSocketGroup(psocketgroupCacheWrite); 00313 } 00314 #ifdef LOG_CHAIN_STATISTICS 00315 /* also add empty packets to the queue (will do nothing, but 00316 * adds the received packet to the statistics) 00317 */ 00318 else { 00319 currentChain->addDataToUpstreamQueue(pChainCell->sequelCell.data, payloadLength); 00320 } 00321 #endif 00322 #ifdef LOG_PACKET_TIMES 00323 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_end); 00324 m_pLogPacketStats->addToTimeingStats(*currentQueueEntry, CHANNEL_DATA, true); 00325 #endif 00326 if (lengthAndFlags & CHAINFLAG_STREAM_CLOSED) { 00327 /* close upstream (after sending data) */ 00328 currentChain->closeUpstream(); 00329 } 00330 } 00331 else { 00332 /* invalid payload-length */ 00333 currentChain->signalConnectionError(); 00334 } 00335 } 00336 else { 00337 #ifdef _DEBUG1 00338 CAMsg::printMsg(LOG_DEBUG, "Unknown chain - cannot continue chain.\n"); 00339 #endif 00340 /* we don't know a chain with the specified ID -> create a 00341 * dummy-chain and signal an unknown-chain-error 00342 */ 00343 currentChain = m_pChainTable->createEntry(); 00344 if (currentChain == NULL) { 00345 /* we are unable to create a new chain (maximum number of 00346 * chains - defined in MAX_POLLFD - is reached) 00347 */ 00348 CAMsg::printMsg(LOG_INFO, "Unable to create more than %u chains - cannot send 'unknown chain' response.\n", MAX_POLLFD); 00349 delete channelCipher; 00350 channelCipher = NULL; 00351 /* currently we have to send at least a CHANNEL-CLOSE -> reuse 00352 * our buffers for the response 00353 */ 00354 getRandom(currentMixPacket->data, DATA_SIZE); 00355 currentMixPacket->flags = CHANNEL_CLOSE; 00356 #ifdef LOG_PACKET_TIMES 00357 /* set invalid packet time for the response */ 00358 setZero64(pQueueEntry->timestamp_proccessing_start); 00359 #endif 00360 m_pQueueSendToMix->add(currentMixPacket, sizeof(tQueueEntry)); 00361 m_logDownloadedPackets++; 00362 /* process the next packet */ 00363 continue; 00364 } 00365 currentChain->addChannel(m_pChannelTable->add(currentMixPacket->channel, channelCipher, currentChain), ((lengthAndFlags & CHAINFLAG_FAST_RESPONSE) == CHAINFLAG_FAST_RESPONSE)); 00366 currentChain->signalUnknownChain(); 00367 } 00368 } 00369 } 00370 else { 00371 /* it's not the first channel-packet -> currently only one upstream- 00372 * packet is allowed -> ignore this one 00373 */ 00374 CAMsg::printMsg(LOG_INFO, "Received more than one packet on a channel.\n"); 00375 } 00376 } 00377 } 00378 00379 //end Step 1 00380 00381 //Step 2 Sending to Cache... 00382 00383 /* check for chains which have data in the upstream-queue (only those 00384 * chains are in the socket-group) and having also a send-ready socket 00385 */ 00386 SINT32 sendReadySockets = psocketgroupCacheWrite->select(0); 00387 if (sendReadySockets > 0) { 00388 bAktiv=true; 00389 #ifdef HAVE_EPOLL 00390 CAChain* currentChain = (CAChain*)psocketgroupCacheWrite->getFirstSignaledSocketData(); 00391 while (currentChain != NULL) { 00392 add64((UINT64&)m_logUploadedBytes, currentChain->sendUpstreamData(MIXPACKET_SIZE, psocketgroupCacheWrite)); 00393 currentChain = (CAChain*)(psocketgroupCacheWrite->getNextSignaledSocketData()); 00394 } 00395 #else 00396 CAChain* currentChain = m_pChainTable->getFirstEntry(); 00397 while ((currentChain != NULL) && (sendReadySockets > 0)) { 00398 if (currentChain->isSignaledInSocketGroup(psocketgroupCacheWrite)) { 00399 sendReadySockets--; 00400 add64((UINT64&)m_logUploadedBytes, currentChain->sendUpstreamData(MIXPACKET_SIZE, psocketgroupCacheWrite)); 00401 } 00402 currentChain = m_pChainTable->getNextEntry(); 00403 } 00404 #endif 00405 } 00406 00407 //End Step 2 00408 00409 //Step 3 Reading from Cache.... 00410 00411 #define MAX_MIXIN_SEND_QUEUE_SIZE 1000000 00412 psocketgroupCacheRead->select(0); 00413 if (m_pQueueSendToMix->getSize() < MAX_MIXIN_SEND_QUEUE_SIZE) { 00414 /* we are able to send data to the previos mix -> ask every chain 00415 * whether we can process something 00416 */ 00417 CAChain* currentChain = m_pChainTable->getFirstEntry(); 00418 while (currentChain != NULL) { 00419 #ifdef LOG_PACKET_TIMES 00420 /* timestamps are only meaningful, if a packet is created and sent, 00421 * in the other case they will be overwritten by the next chain 00422 */ 00423 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_start); 00424 set64(currentQueueEntry->timestamp_proccessing_start_OP, currentQueueEntry->timestamp_proccessing_start); 00425 #endif 00426 UINT32 processedBytes; 00427 SINT32 status = currentChain->processDownstream(psocketgroupCacheRead, currentMixPacket, &processedBytes); 00428 add64((UINT64&)m_logDownloadedBytes, processedBytes); 00429 if ((status == 0) || (status == 2)) { 00430 /* there was a packet created -> send it */ 00431 #ifdef LOG_PACKET_TIMES 00432 getcurrentTimeMicros(currentQueueEntry->timestamp_proccessing_end_OP); 00433 #endif 00434 m_pQueueSendToMix->add(currentMixPacket, sizeof(tQueueEntry)); 00435 m_logDownloadedPackets++; 00436 } 00437 if ((status == 2) || (status == 3)) { 00438 /* chain can be removed from the table */ 00439 m_pChainTable->deleteEntry(currentChain->getChainId()); 00440 } 00441 currentChain = m_pChainTable->getNextEntry(); 00442 } 00443 } 00444 00445 //end Step 3 00446 00447 //Step 4 Writing to previous Mix 00448 // Now in a separate Thread! 00449 //end step 4 00450 00451 if (!bAktiv) { 00452 /* there was no data to process in upstream and downstream direction 00453 * -> avoid senseless looping and sleep some time 00454 */ 00455 msSleep(100); 00456 } 00457 /* go again to the begin */ 00458 } 00459 00460 /* we have leaved the mix-loop */ 00461 CAMsg::printMsg(LOG_CRIT, "Seams that we are restarting now!\n"); 00462 m_bRestart=true; 00463 m_pMuxIn->close(); 00464 /* write some bytes to the queue (ensure that m_pthreadSendToMix will stop) 00465 */ 00466 UINT8 b[sizeof(tQueueEntry)+1]; 00467 m_pQueueSendToMix->add(b, sizeof(tQueueEntry)+1); 00468 CAMsg::printMsg(LOG_CRIT, "Wait for LoopSendToMix...\n"); 00469 /* will not join if queue is empty (because thread is waiting)!!! */ 00470 m_pthreadSendToMix->join(); 00471 m_bRunLog = false; 00472 CAMsg::printMsg(LOG_CRIT, "Wait for LoopReadFromMix...\n"); 00473 m_pthreadReadFromMix->join(); 00474 #ifdef LOG_PACKET_TIMES 00475 CAMsg::printMsg(LOG_CRIT, "Wait for LoopLogPacketStats to terminate...\n"); 00476 m_pLogPacketStats->stop(); 00477 #endif 00478 /* delete the tables (will also remove all entries) */ 00479 delete m_pChainTable; 00480 m_pChainTable = NULL; 00481 delete m_pChannelTable; 00482 m_pChannelTable = NULL; 00483 delete currentQueueEntry; 00484 currentQueueEntry = NULL; 00485 pLogThread->join(); 00486 delete pLogThread; 00487 pLogThread = NULL; 00488 delete psocketgroupCacheWrite; 00489 psocketgroupCacheWrite = NULL; 00490 delete psocketgroupCacheRead; 00491 psocketgroupCacheRead = NULL; 00492 #endif //NEW_MIX_TYPE 00493 return E_UNKNOWN; 00494 } 00495 #endif //ONLY_LOCAL_PROXY
1.7.6.1