From Gnutella Developers
Source - [Latest draft (http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html)]
3.4.1 Requirements for a pong cache implementation
There are different systems for handling Ping and Pong messages, but what they have in common is:
* When a Ping message is received (TTL>1 and it was at least one second since another Ping was received on that connection), a servent MUST, if possible, respond with a number of Pong Messages. These pongs MUST have the same message ID as the incoming ping, and a TTL no lower than the hops value of the ping. The number of pongs returned may vary, but 10 is a reasonable number. Servents that are able to accept incoming Gnutella SHOULD reply to these Ping messages.
* The pongs sent SHOULD have a good quality. That includes high probability that they are connectable and a good spread of hosts from across the network
* The bandwidth used by Ping and Pong messages SHOULD be minimized. Servents MUST never output very high quantities of Ping and Pong messages.
* An incoming Ping message with TTL = 1 and Hops = 0 or 1 is used to probe the remote host of a connection, and MUST always be replied to with a pong having information about the host who received the ping.
* An incoming Ping message with TTL = 2 and Hops = 0 is a "Crawler Ping" used to scan the network. It and SHOULD be replied to with pongs containing information about the host receiving the ping and all other hosts it is connected to. The information about neighbour nodes can be provided either by creating pongs on their behalf, or by forwarding the ping to them, and forward the pongs returned to the crawler.
Servents fulfilling these requirements MUST provide the header "Pong-Caching: 0.1" (or a higher number if a later version is used) during the handshake. That allows other nodes to know if pong caching in any form is supported. Note that this applies to servents do not really cache pong messages as well, as long as the rules above apply. Servents are strongly RECOMMENDED to follow the rules above, and provide the Pong-Caching header.
When storing or forwarding Pong messages, any GGEP payload SHOULD be included. When sending a Ping message, one cannot know if it will reach only the neighbour host, or many hosts on the network. It depends on what system for handling Ping and Pong messages other servents are using. Servents MUST NOT make assumptions of how far a Ping message (and its payload) will reach.
3.4.2 A simple pong caching scheme
This is one system for handling Ping and Pong messages. There are others available (see 3.4.3), and any system that abides to the rules in sect. 3.4.1 is ok.
For each connection an array of Pong Messages are stored. 10 may be a good number. When a pong comes in, it overwrites the oldest stored pong in array of he connection the pong came from. The information that must be stored for each pong is:
* IP Address * Port number * Number of files shared * Number of kilobytes shared * GGEP extension block (if present) * Hops value, i.e. how far away on the network the host using the stored address is
When a Ping message, called P, is received over connection C, and it has been at least one second since the last time a ping was received over C, the servent will return a number of pongs (10 for example) from its stored pongs. The pongs will be picked from among all connections (except from C, since it would be no good sending pongs back where they came from). A servent should also return a pong with information about itself, if it can accept incoming connections.
The outgoing pong will have the same message ID as P, not the message ID it had when the pong was received. The Hops is set to the stored hops value + 1, and TTL so that TTL+Hops=7. If the TTL is less than P's Hops value, the current stored pong will not be sent. This also means that pongs whose Hops value already is 7 will not be propagated any further.
Exactly how to select which of the stored pongs to send in response to an incoming ping is up to each servent. A good idea is to pick pongs from different connections and with varying stored Hops values.
To keep the cache fresh, a ping (TTL=7, Hops=0) is sent over all connections at small intervals (like every 3 seconds). This look like very often, but remember that the neighbour servents will just respond with pongs from their own caches. The short time ensures that pongs are always fresh. To neighbour hosts who have not indicated that they support pong caching (using the Pong-Caching handshaking header), one ping per minute might be a better number.
Incoming pings with TTL=1 and Hops=0 or 1 (see above section 2.2.4) are replied to with a single pong containing information about the local host. Pings with TTL=2 and Hops=0 are replied to with one pong about the local host, and one about each other host the local host is connected to. Information about the neighbour hosts is retrieved when a new connection is started by sending a TTL=1, Hops=0 ping and storing the pong returned. This can be done using handshaking headers instead.
The bandwidth used by this scheme is very limited. Assume a ping is sent every 3 seconds and that 10 pongs are returned to every ping. Since each ping (without extensions) is 23 bytes and a pong (without extensions) is 37 bytes, the amount of bandwidth used per connection is (23+10*37)/3 = 131 bytes/sec/connection. If extensions are used in ping and/or pong messages, the bandwidth usage will increase, but will still be kept to an acceptable level. If the bandwidth usage must re-decreased further, the interval between update pings could be increased.
3.4.3 Other pong caching schemes
A slightly more advanced scheme for pong caching was proposed by LimeWire : LimeWire's Pong Caching http://rfc-gnutella.sourceforge.net/src/pong-caching.html
A different, but compatible scheme for ping reduction has been written by Mike Green: ping reduction http://rfc-gnutella.sourceforge.net/src/pingreduce.html
Another scheme was derived from the last one: another ping reduction scheme http://rfc-gnutella.sourceforge.net/src/pingreduce2.html
Other schemes might have been created after this was written.