Developers.Code.CHandshakes

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

CHandshakes

CHandshakes doesn't inherit from another class. But, it is closely related to CHandshake, which inherits from CConnection. So, to document this part of the code, I've got CConnection, CHandshake and CHandshakes across the tabs at the top of Visual Studio.

Here are a few lines from the top of Handshake.cpp:

[code Handshake.cpp]

  1. define new DEBUG_NEW
  2. endif

CHandshake::CHandshake() { </source>

Note how there is nothing between the #endif and the constructor. Now, compare that to Handshakes.cpp:

[code Handshakes.cpp]

  1. define new DEBUG_NEW
  2. endif

CHandshakes Handshakes;

CHandshakes::CHandshakes() { </source>

There is an extra line. Outside of a method, the program says CHandshakes Handshakes;. What does this mean? It is a definition with a type followd by a variable name, like int i. If we typed int i up there, the program would create a global integer when it runs, accessible to all the code in this file. That's what Handshakes is: a global CHandshakes object that gets created when the program runs, and deleted when it exits.

When Shareaza is running, there is just one CHandshakes object. If you search the code for new CHandshakes, you don't find anything.

CHandshake represents a connection to a remote computer. There are a lot of them. They get created and destroyed as we connect and disconnect from computers.

CHandshakes keeps our list of CHandshake objects. There is only one. It gets created when the program runs, and destroyed when it exits.

CHandshakes has its own socket. This is not the same as the socket in CConnection, which CHandshake inherits. The one CHandshakes object has one socket, which it sets up as a listening socket. Remote computers on the Internet can contact us with this socket. When one does, code accepts the connection with a new socket in a new CHandshake object. The listening socket is still there, listening for more connections.

Constructor and Destructor

When Shareaza runs, your computer executes this line of code at the top of Handshakes.cpp:

[code Handshakes.cpp] CHandshakes Handshakes; </source>

It creates one new global CHandshakes object, named Handshakes, and calls the constructor to set it up. The constructor just zeroes and nulls the member variables. The destructor has the Disconnect method put everything away.

Listen

Listen sets up the socket and thread so remote computers can contact us. First, it calls socket to create a new TCP/IP socket, m_hSocket. It calls bind to tell the socket our IP address, and then listen to begin listening.

The method calls AfxBeginThread to start a new thread. The thread's handle is m_hThread, and it runs the method ThreadStart.

Disconnect

There are 3 things that Disconnect needs to clean up.

  1. The socket, m_hSocket, is closed with a call to disconnect.
  2. The thread, m_hThread, is stopped with a call to TerminateThread.
  3. The list of handshake objects, m_pList, is cleared with delete and RemoveAll.

PushTo

The PushTo method takes an IP address and port number, connects to the remote computer, and makes a handshake object for the connection. Most of the work is done by CHandshake::OnPush. This method makes sure we don't already have too many connections open to the remote computer. It also adds the new CHandshake object to the list of them here.

IsConnectedTo, Substitute and Remove

IsConnectedTo takes an IP address, and searches the list of handshake objects for it. Returns true if it is found, false if it's not there. Substitute replaces a handshake object in the list with a new one. Remove takes one out of the list.

ThreadStart and OnRun

The Listen method sets up the socket in the CHandshakes object to listen for incoming connections. This is something that Shareaza has to do all the time. If the program itself did it, it would be frozen, waiting for computers to contact it. It wouldn't be able to draw the window or respond to user clicks at the same time. To solve this problem, Shareaza creates a thread. The thread loops forever, waiting for computers to call us and taking their connections, and then waiting some more.

ThreadStart is the only method the thread runs. The thread begins on the first line of ThreadStart. When ThreadStart returns, the thread is over. ThreadStart just calls the next method in the file, OnRun.

<source lang="c"> while ( m_hSocket != INVALID_SOCKET ) { WaitForSingleObject( m_pWakeup, 1000 ); while ( AcceptConnection() ); RunHandshakes(); while ( AcceptConnection() ); RunStableUpdate(); } </source>

When the thread runs, it gets to the line of code WaitForSingleObject. It stays there until the m_pWakeup event is fired. When a remote computer calls our listening socket, the m_pWakeup event is fired. So, the thread waits for a remote computer's connection. The loop then calls AcceptConnection.

AcceptConnection makes a new CHandshake object for the connection and adds it to the list. OnRun keeps calling AcceptConnection until it returns FALSE. AcceptConnection does this when WSAAccept fails, probably indicating that there aren't any more remote computers who want to connect to us right now.

Next, OnRun calls RunHandshakes. This method goes down the list of handshake objects, reading data from and writing data to each one, and making sure all of them are still open. So, this thread is also responsible for pushing data through all the connections in both directions.

When the main thread calls Disconnect, it sets m_hSocket to INVALID_SOCKET. The thread reaches the top of the while loop, and falls out of it. Control exits OnRun and returns to ThreadStart. When that method exits, so does the thread.

RunHandshakes

One job CHandshakes does is keep a list of all the CHandshake objects. The RunHandshakes method loops down this list, calling CConnection::DoRun on each. DoRun transfers data through the socket in both directions, reading any bytes waiting on our end, and flushing our output buffer to the remote computer.

AcceptConnection and CreateHandshake

AcceptConnection gets called when a computer has contacted the socket we are listening on. It uses WSAAccept to accept the new connection with a new socket, hSocket. It then calls CreateHandshake, which has this line of code:

<source lang="c"> m_pList.AddTail( new CHandshake( hSocket, pHost ) ); </source>

The part new CHandshake creates a new CHandshake object with the socket and the remote computer's IP address. AddTail sticks it on the end of the list of handsakes.

AcceptCheck

AcceptCheck has a lot of weird parameters because it is hooked to WSAAccept, as described here in the MSDN Library. All it really has to do is return CF_ACCEPT or CF_REJECT. If it returns CF_REJECT, WSAAccept won't complete the connection with the remote computer.

Before accepting a connection, AcceptCheck makes sure Windows knows the remote computer's IP address, and that it's not on Shareaza's list of government and corporate IP addresses to avoid.

RunStableUpdate

RunStableUpdate is part of the loop the thread runs listening on the socket and accepting connections. It calls DiscoveryServices.Update.