Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

PacketBuffer.cpp

Go to the documentation of this file.
00001 //
00002 // PacketBuffer.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 // CG1PacketBuffer holds arrays of packets to send, organized by their type
00023 // http://wiki.shareaza.com/static/Developers.Code.CG1PacketBuffer
00024 
00025 // Copy in the contents of these files here before compiling
00026 #include "StdAfx.h"
00027 #include "Shareaza.h"
00028 #include "Settings.h"
00029 #include "PacketBuffer.h"
00030 #include "G1Packet.h"
00031 #include "Neighbours.h"
00032 #include "Buffer.h"
00033 #include "Statistics.h"
00034 
00035 // If we are compiling in debug mode, replace the text "THIS_FILE" in the code with the name of this file
00036 #ifdef _DEBUG
00037 #undef THIS_FILE
00038 static char THIS_FILE[]=__FILE__;
00039 #define new DEBUG_NEW
00040 #endif
00041 
00043 // CG1PacketBuffer construction
00044 
00045 // Takes access to a buffer to write packets to directly instead of keeping them in this new object
00046 // Makes a new CG1PacketBuffer object that holds 9 arrays of 64 packets each, one array for each packet type
00047 CG1PacketBuffer::CG1PacketBuffer(CBuffer* pBuffer)
00048 {
00049         // Make an array of 9 new CG1PacketBufferType objects, each of which are an array of 64 packets
00050         m_pType = new CG1PacketBufferType[ G1_PACKTYPE_MAX ]; // One array for each packet type, like ping or pong
00051 
00052         // Save given pointer to a buffer in the object
00053         m_pBuffer  = pBuffer;
00054 
00055         // Initalize values
00056         m_nTotal   = 0; // The total number of packets we've added to empty spots in arrays
00057         m_nCycle   = 1; // What kind of packet to send next, like 1 ping, 2 pong, and so on
00058         m_nIterate = 0; // Start out the count of packets of a type we've sent as 0
00059         m_nDropped = 0; // The total number of packets we've overwritten in the arrays because of lack of room
00060 }
00061 
00062 // Delete this CG1PacketBuffer object
00063 CG1PacketBuffer::~CG1PacketBuffer()
00064 {
00065         // Tell all the packets in the arrays for each type that we're not linked to them from here anymore
00066         Clear();
00067 
00068         // Delete the array of 9 CG1PacketBufferType objects
00069         delete [] m_pType;
00070 }
00071 
00073 // CG1PacketBuffer add
00074 
00075 // Takes a Gnutella packet and true to put it in the buffer, false to put it in the arrays
00076 void CG1PacketBuffer::Add(CG1Packet* pPacket, BOOL bBuffered)
00077 {
00078         // If the packet isn't buffered yet, or doesn't have a type like ping or pong yet
00079         if ( ! bBuffered || ! pPacket->m_nTypeIndex )
00080         {
00081                 // Write the packet directly into the buffer, and we're done
00082                 pPacket->ToBuffer( m_pBuffer );
00083                 return;
00084         }
00085 
00086         // If the packet is already buffered, or it has a known type like ping or pong, add it to the appropriate array
00087         BOOL bFresh =                 // Add will tell us if it added the packet in an empty spot, or overwrote a packet
00088                 m_pType                   // The array of packet arrays for each type
00089                 [ pPacket->m_nTypeIndex ] // The type of the packet, like ping or pong, brings us to the array for that type
00090                 .Add( pPacket );          // Add the packet to that array
00091 
00092         // Add had an empty spot in the array for the new packet
00093         if ( bFresh )
00094         {
00095                 // Add the added packet to the total
00096                 m_nTotal++;
00097 
00098         } // Add had to overwrite a packet because there are already 64 of that type there
00099         else
00100         {
00101                 // Count the packet that was overwritten as dropped and lost
00102                 m_nDropped++;
00103                 Statistics.Current.Gnutella1.Lost++; // Our count of how many packets we lost before being able to send
00104         }
00105 }
00106 
00108 // CG1PacketBuffer packet selection
00109 
00110 // Takes an expiration time
00111 // Gets a packet to send, choosing one added recently and of a different type than the one before
00112 // Returns the packet
00113 CG1Packet* CG1PacketBuffer::GetPacketToSend(DWORD dwExpire)
00114 {
00115         // Let the loop send as many as
00116         static int nVolumeByType[ G1_PACKTYPE_MAX ] = {
00117                 0,   // 0 unknown packets at a time
00118                 1,   // 1 pign packet at a time
00119                 2,   // 2 pong packets at a time
00120                 5,   // 5 bye packets at a time
00121                 1,   // 1 query route packet at a time
00122                 1,   // 1 vendor specific packet at a time
00123                 5,   // 5 push packets at a time
00124                 1,   // 1 query packet at a time
00125                 4 }; // 4 query hit packets at a time
00126 
00127         // Loop
00128         for (
00129 
00130                 // Start nCycle as 18
00131                 int nCycle = G1_PACKTYPE_MAX * 2; // The local variable nCycle isn't used in the loop, just up here
00132 
00133                 // Stop if nCycle is 0
00134                 nCycle; // This would mean we've looped 18 times
00135 
00136                 // After each loop, do all of the following
00137                 nCycle--,        // nCycle will be like 18, 17, 16, ... 2, 1, and then 0 will break the loop
00138                 m_nCycle++,      // Move to the next packet type array, like from 1 ping to 2 pong and so on
00139                 m_nIterate = 0 ) // Reset the count of packets of this type we've sent to 0
00140         {
00141                 // Cycle from ping 1, to pong 2, to bye 3, and so on
00142                 m_nCycle %= G1_PACKTYPE_MAX; // Divide m_nCycle by 9 and take the remainder, which is 0 through 8
00143                 if ( ! m_nCycle ) continue;  // If that produced 0 unknown packet type, skip the rest of the code in the loop and loop again
00144 
00145                 // If we've sent more packets of this type than the list of limits above allows, skip the rest of the loop code and loop again
00146                 if ( m_nIterate >= nVolumeByType[ m_nCycle ] ) continue; // How could m_nIterate ever get above 1? (do)
00147 
00148                 // Get the most recently added and not expired packet of the type determined by cycle
00149                 CG1Packet* pPacket =    // Get a pointer to a packet
00150                         m_pType[ m_nCycle ] // The array of 64 packets of m_nCycle type, like 1 ping first, then 2 pong, and so on
00151                         .Get(               // Get the most recently added and not expired packet from that array
00152                                 dwExpire,       // Tell Get the expiration time
00153                                 &m_nTotal,      // Get will update the total number of packets added in empty slots and dropped here
00154                                 &m_nDropped );
00155 
00156                 // If we got a packet
00157                 if ( pPacket )
00158                 {
00159                         // Increment iterate and return it
00160                         m_nIterate++;   // Count that we've found a packet and the program will send it
00161                         return pPacket; // Return the packet to the caller so it can send it
00162                 }
00163         }
00164 
00165         // We don't have any more packets to send
00166         return NULL;
00167 }
00168 
00170 // CG1PacketBuffer clear
00171 
00172 // Clears all the packets from all the arrays
00173 void CG1PacketBuffer::Clear()
00174 {
00175         // Loop through the 9 arrays of 64 packets, one array for each packet type
00176         for ( int nType = 0 ; nType < G1_PACKTYPE_MAX ; nType++ )
00177         {
00178                 // Clear this array
00179                 m_pType[ nType ].Clear();
00180         }
00181 
00182         // Reset the count of how many packets we've added in empty array spots
00183         m_nTotal = 0;
00184 }
00185 
00187 // CG1PacketBufferType construction
00188 
00189 // Create a new array of packet pointers
00190 CG1PacketBufferType::CG1PacketBufferType()
00191 {
00192         // Set the number of Gnutella packets this CG1PacketBufferType object will point to from the program settings
00193         m_nCapacity     = Settings.Gnutella1.PacketBufferSize; // By default, it's 64
00194 
00195         // Make the arrays of packet pointers and times
00196         m_pBuffer = new CG1Packet*[ m_nCapacity ]; // Allocate an array of 64 pointers to Gnutella packets, and point m_pBuffer at this array
00197         m_pTime   = new DWORD[ m_nCapacity ];      // Make an array of 64 DWORDs to record the time each packet will expire
00198 
00199         // Start packet indices and counts at 0
00200         m_nHead  = 0; // This is the index where we will add a packet to the array, initialize to 0 even though we'll add them back to front
00201         m_nCount = 0; // We haven't added any packets to the array yet
00202 }
00203 
00204 // Delete this array of packet pointers
00205 CG1PacketBufferType::~CG1PacketBufferType()
00206 {
00207         // Clear all the packet pointers from the array, and reset the count and head values to 0
00208         Clear(); // Tells each packet that we're not pointing to it anymore
00209 
00210         // Free the memory of the pointer and DWORD arrays we allocated in the constructor
00211         delete [] m_pTime;
00212         delete [] m_pBuffer;
00213 }
00214 
00216 // CG1PacketBufferType add
00217 
00218 // Takes a pointer to a Gnutella packet
00219 // Adds it and its expiration time to the arrays inside this CG1PacketBufferType object, going from end to start
00220 // Returns false if the array was full and we overwrote a packet, true if we're still on the first sweep backwards
00221 BOOL CG1PacketBufferType::Add(CG1Packet* pPacket)
00222 {
00223         // Assume that there is room for one more packet
00224         BOOL bFresh = TRUE;
00225 
00226         // If the arrays are full, we'll put this packet in the last place again and fill backwards from there again
00227         if ( m_nCount == m_nCapacity ) // Count and capacity are both 64
00228         {
00229                 // Record there is one fewer packet in the array
00230                 m_nCount--; // Now count is 63
00231 
00232                 // Call Release on the last packet in the buffer, then the one before that, then (do)
00233                 m_pBuffer[                 // Look at an index in the buffer of arrays we are about to calculate
00234                         ( m_nHead + m_nCount ) // Head + count are usually 64, but we just decremented count so now they're 63
00235                         % m_nCapacity ]        // Divide by 64 and take the remainder, which is 63
00236                         ->Release();           // Release the last packet in the array, the one at index 63
00237 
00238                 // Note that no, there wasn't room for another packet, but we made room so it's OK
00239                 bFresh = FALSE;
00240         }
00241 
00242         // Count head down each time this line runs like 63, 62, 61 ... 3, 2, 1, 0, 63, 62, 61 ... to sweep backwards down the array
00243         if ( ! m_nHead-- ) m_nHead += m_nCapacity; // If head is 0, add capacity to it, and also decrement it either way
00244 
00245         // Record there will be one more packet stored here
00246         m_nCount++; // If we are overwriting packets now, this will set the count back up to 64
00247 
00248         // Store a pointer to the packet and the time a minute from now when it will expire at the head index of the arrays
00249         m_pBuffer[ m_nHead ] = pPacket;          // Store the pointer to the packet
00250         m_pTime[ m_nHead ] =                     // A minute from now, the packet we're adding will expire
00251                 GetTickCount() +                     // The tick count now
00252                 Settings.Gnutella1.PacketBufferTime; // By default, this is 1 minute
00253 
00254         // Have the packet count one more pointer saved to it
00255         pPacket->AddRef();
00256 
00257         // Return true if we did that without making more room, or false if we did it after making more room
00258         return bFresh;
00259 }
00260 
00261 // Takes an expiration time, and access to 2 integers to write statistics
00262 // Gets the packet we added most recently that hasn't expired, and moves head forward and decrements count
00263 // Returns a pointer to it
00264 CG1Packet* CG1PacketBufferType::Get(DWORD dwExpire, int* pnTotal, int* pnDropped)
00265 {
00266         // Local variables
00267         CG1Packet* pPacket; // A pointer to a packet copied from the array of packet pointers
00268         DWORD dwPacket;     // The expiration time of that packet
00269 
00270         // Loop until we find a packet that hasn't expired
00271         do
00272         {
00273                 // If there aren't any packet pointers in the array, we won't be able to find this one
00274                 if ( ! m_nCount ) return NULL; // Not found
00275 
00276                 // Get the packet pointer and time we most recently added to the arrays
00277                 pPacket  = m_pBuffer[ m_nHead ]; // The pointer the Add method added the last time it ran
00278                 dwPacket = m_pTime[ m_nHead ];   // The tick count 1 minute after it ran
00279 
00280                 // Move forward in the array to the next most recently added packet
00281                 m_nHead = ( m_nHead + 1 ) % m_nCapacity; // Add 1 to head unless it is 63, then take it back to 0
00282 
00283                 // This packet is either expired, or will be returned, so we can record 1 less packet in the array
00284                 m_nCount--;
00285 
00286                 // This packet has expired
00287                 if ( dwPacket < dwExpire ) // This packet's expiration date happened before the given expiration date
00288                 {
00289                         // Adjust the numbers the caller gave us access to
00290                         if ( pnTotal )   (*pnTotal)--;   // This is one less packet total
00291                         if ( pnDropped ) (*pnDropped)++; // This is one more packet dropped
00292 
00293                         // Count this in statistics as a lost packet
00294                         Statistics.Current.Gnutella1.Lost++;
00295 
00296                         // Tell the packet we're no longer pointing to it from here
00297                         pPacket->Release();
00298                         pPacket = NULL; // Stay in the do while loop
00299                 }
00300         }
00301         while ( pPacket == NULL ); // If the if statement didn't run, exit the do while loop
00302 
00303         // Return the pointer to the first packet we found that hasn't expired
00304         return pPacket;
00305 }
00306 
00307 // Clears all the packet pointers from the array, and resets the count and head values to 0
00308 void CG1PacketBufferType::Clear()
00309 {
00310         // If count is 5, loop for 5, 4, 3, 2, and 1, set count to 0, and don't enter the loop
00311         while ( m_nCount-- > 0 ) // Enter the loop if count is positive, and then decrement the count
00312         {
00313                 // Tell each packet we're not pointing to it anymore
00314                 m_pBuffer[ ( m_nHead + m_nCount ) % m_nCapacity ]->Release();
00315         }
00316 
00317         // Count is 0, reset head to that value also
00318         m_nHead = 0;
00319 }
00320 

Generated on Thu Dec 15 10:39:45 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2