Node Route Cache and Addressed Packet Forwarding
Each Gnutella2 node must maintain a dynamic node route cache to map node GUIDs to appropriate destinations. The route cache is consulted when a packet needs to be dispatched to, or toward a GUID-addressed node. GUID-addressing is used over network-addressing in a number of situations.
Each entry in a node route cache will have:
- The GUID of the target node
- The local TCP connection providing the best route to the node, or
- A UDP endpoint for the node or the best route to the node
A route cache needs to be addressable by GUID, and must implement a refresh mechanism to store routes for an appropriate amount of time based upon route hits. Many schemes exist to engineer efficient lookup systems, such as hash tables, twotable exchanges and balanced trees.
The route cache is similar to the several GUID mapping caches involved in old Gnutella applications, with two key differences:
- Each entry may map to a local address or a UDP endpoint
- There is only one unified route cache for all purposes
GUIDs are used to identify virtual entities within the network, such as nodes (node GUIDs), searches (search GUIDs) and other transactional requests. The GUIDs associated with these entities can then be committed to the route cache and mapped to reflect the easiest route back to the owner of the object.
All nodes should be aware of their directly connected neighbours, and treat these node GUIDs as a special case that need never expire.
Addressed Packet Forwarding
Any Gnutella2 packet may be addressed to a particular destination node by GUID. Upon receiving an addressed packet, it should be immediately forwarded either to the destination, or toward it. Addressed packets should not be interpreted locally, unless the destination address matches the local GUID.
Loops are avoided by placing restrictions upon forwarding:
- If received from a leaf via TCP, a packet may be forwarded anywhere
- If received from a hub, a packet may only be forwarded to a leaf
- If received via UDP, a packet may not be forwarded via UDP
Note that these restrictions apply only to generically addressed packets. Some packet types have specific forwarding rules which override these. These rules allow any node to be reached in two hops.
Packets are addressed by including a special child packet as the first child of the root packet. The child packet is named "TO", so its full name would be "/?/TO" where ? is the root packet name. The address packet's payload consists of a 16 byte GUID, and it has no children defined at the current time.
Reverse Connection (Push) Requests
Addressed packet forwarding can be used to deliver any valid Gnutella2 communications to leaf nodes that are unable to accept TCP or UDP traffic directly. The packet is simply sent to one of the hubs to which the target leaf is attached, or a hub in the same hub cluster, and the forwarding rules will allow the packet to reach its destination.
This mechanism is used to request that a "firewalled" leaf initiate a "reverse connection" or "call-back" to an elected address. The root packet type "/PUSH" is used.
The Gnutella2 push handshake is very simple - it simply identifies the connection as originating from a push, and provides the GUID of the initiating node:
PUSH guid:GUIDinHEXguidINhexGUIDinHEXguidI (\r\n) (\r\n)
Note that unlike the Gnutella1 case, no purpose-specific information is provided. The pushed connection can now be used for any purpose a normally established TCP link could adopt, including, but not limited to:
- Gnutella2 network connection
- Data transfer
- Personal communications
Gnutella2 implementations are however, strongly advised to provide backward support for the Gnutella1 push handshake, even if not supporting Gnutella1 directly. This is because applications supporting both protocols may be unable to determine in advance, whether the host they are pushing to is Gnutella1 or Gnutella2. The legacy-style push handshake looks like:
GIV 0:GUIDinHEXguidINhexGUIDinHEXguidI/ (\n\n)
The leading zero and trailing slash have task-specific meanings in Gnutella1; however Gnutella2 applications can safely ignore them and consider only the GUID. Be sure to allow for variable length handshakes, however.