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