Developers.Code.CShakeNeighbour.Running

From Shareaza Wiki
Revision as of 20:07, 20 June 2009 by Kevogod (talk | contribs) (1 revision)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

How ShakeNeighbour Works

This is how the code of the CShakeNeighbour class in Shareaza negotiates the handshake with a remote computer. First, here is a summary of what the complete handshake looks like:

<source lang="c"> We initiated the connection The remote computer connected to us

Us Them Us Them

GNUTELLA CONNECT/0.6 GNUTELLA CONNECT/0.6 More-Headers (2) \r\n More-Headers (1) \r\n

                       GNUTELLA/0.6 200 OK    GNUTELLA/0.6 200 OK
                       (2)                    More-Headers
                       More-Headers           \r\n
                       \r\n                   (1)

GNUTELLA/0.6 200 OK GNUTELLA/0.6 200 OK More-Headers (3) \r\n More-Headers (1) \r\n </source>

There are always 3 groups of headers. If we initiated the connection to the remote computer, we send the first and third groups. If the remote computer contacted us, we send the second. The core of handshake negotiation in Shareaza is CShakeNeighbour::OnRead:

<source lang="c"> BOOL CShakeNeighbour::OnRead() {

   CConnection::OnRead();
   if ( m_nState == nrsHandshake1 && ! ReadResponse() ) return FALSE;
   if ( m_nState == nrsHandshake2 && ! ReadHeaders()  ) return FALSE;
   if ( m_nState == nrsHandshake1 && ! ReadResponse() ) return FALSE;
   if ( m_nState == nrsHandshake3 && ! ReadHeaders()  ) return FALSE;
   if ( m_nState == nrsRejected   && ! ReadHeaders()  ) return FALSE;
   return TRUE;

} </source>

The numbers in the top diagram show how Shareaza sets m_nState as it reads the handshake. nrsHandshake1 means we've just finished sending a group of headers, and it's time for ReadResponse to see how the remote computer starts its next group. nrsHandshake2 means we are reading the first group of headers from the remote computer. nrsHandshake3 means we are reading the remote computer's final group of headers. In both states, ReadHeaders reads each header.

In the code, OnRead gets called repeatedly. Depending on how complete the handshake is, control flows further and further down the path shown here:

File:Handshakestate.png

OnRead calls ReadResponse when the state is 1 and we are waiting for the remote computer to send us a new group of headers. When the first line of the group arrives, ReadResponse makes sure it is not a refusal and changes the state to 2 or 3. This causes OnRead to call ReadHeaders. This method keeps reading headers, taking in IP addresses to try and setting member variables that represent abilities the remote computer is advertising. When ReadHeaders runs out, the header block is done. Control passes to OnHeadersComplete, which checks that the connection is valid according to the rules for ultrapeer and leaves.

If ReadResponse or OnHeadersComplete detect the whole handshake is done, they call OnHandshakeComplete. This method creates a new CG1Neighbour or CG2Neighbour object and copies the contents of this one into its core. The new object is specialised for the Gnutella or Gnutella2 network now that the handshake is over.