Developers.Code.CNeighboursBase
CNeighboursBase
CNeighboursBase is the base class of a long inheritance column. At the top of the column is CNeighbours - the only class that Shareaza actually makes an object out of. Mike programmed this part of Shareaza this way just to separate out the tasks CNeighbours has to do.
To begin this functionality, CNeighboursBase defines an MFC collection class map that holds a bunch of CNeighbour objects. Each CNeighbour object represents our connection to a remote computer. So, if you want to tell each computer something, or count how many computers we are connected to right now, you use this list.
The list is a MFC CMapPtrToPtr object named m_pUniques. To add a new neighbour object to the list, call Add. To remove one, call Remove.
Methods in CNeighboursBase make it easy to loop through the list. Call GetIterator to get a POSITION value, and then give it to GetNext to get each CNeighbour pointer.
Each object in the list has a unique number, like 2, 3, 4, and so on. To find the neighbour object with a number like that, call Get(DWORD nUnique). If you have an IP address and want to find out if we are connected to it, search with Get(IN_ADDR* pAddress) instead.
To count how many connections we have, or how many we have of a certain type, call GetCount.
Collection classes
Programs make objects to represent things they are working with. For instance, when Shareaza connects to a remote computer on the Internet, it makes a CNeighbour object to represent that computer. The CNeighbour object has member variables that keep track of what we know about the remote computer, and methods that help us exchange information with it.
Shareaza has a lot of CNeighbor objects - one for each computer it's connected to. It needs to keep all these objects in a list. This is where collection classes come in. Languages like C++ and platforms like MFC have classes called collection classes to solve exactly this problem. Collection classes let a program keep a bunch of objects together, in a collection like an array or a list.
Sharaza's CNeighbours class is all about keeping a list of computers we are connected to and exchanging information with. So, it makes sense that collection classes become important here.
MFC collection classes
In the MSDN Library, the documentation for CMapPtrToPtr links to a document about MFC collection classes. It looks like there are two different kinds of MFC collection classes. First are the old ones from MFC 1.0, like CPtrList and CMapPtrToPtr. Shareaza uses these. Later, MFC made new collection classes that use C++ templates. They have names like CList and CTypedPtrList. Newer parts of Shareaza use these.
The map collection class
One of MFC's CMapPtrToPtr collection class is a map collection class. As its name suggests, CMapPtrToPtr maps a pointer to one object to a pointer to another object. The first object, used to look things up, is called the key object. The second object, the one that is the result of your lookup, is the value object.
You could use CMapPtrToPtr to program an English dictionary. For the key objects, use pointers to strings like "car" and "book". For the value objects, use pointers to strings, like "A machine used for transportation on roads" and "Printed pages, bound together, containing text". Load each key and value pair into the map object, and then lookup keys to retrieve the values.
Run cookie?
The class CNeighboursBase defines a member DWORD called m_nRunCookie. The constructor initializes its value to 5. What is it? It's used 3 places in OnRun:
<source lang="c"> void CNeighboursBase::OnRun() { m_nRunCookie++;
for ( POSITION pos = GetIterator() ; pos ; ) { CNeighbour* pNeighbour = GetNext( pos );
if ( pNeighbour->m_nRunCookie != m_nRunCookie ) { pNeighbour->m_nRunCookie = m_nRunCookie; </source>
The code loops through all the neighbours in the list. When it finds one with a mismatching run cookie count, it enters an if block where it brings the count up to date. The rest of the code in the if block adds the information from this neighbour to the totals we are calculating for all of them. So, the cookie count is used to make sure that the loop doesn't hit the same neighbour twice. If it did, the neighbour's cookie count would match the CNeighboursBase member variable, and control would skip over the if block.
Of course, this code also shows that CNeighbour has a cookie count just like CNeighboursBase. Both are named m_nRunCookie. The CNeighbour constructor doesn't initialize the cookie to anything, so it's initial value might be 0 or just random data from the computer's memory. The first time the code above runs, it won't be 5, control will enter the if block, and it will get set to 5. The next time the method above runs, it will be tested against 6 and then set to 6.
If GetIterator and GetNext work properly, none of this should be necessary. I'm actually not sure why it is.
My guess is that Mike named this "run cookie" because this is the cookie we use to see how many times an object has been run. Like a Web site placing a cookie on your hard drive, CNeighboursBase puts this cookie in each CNeighbour object in the list. It's similar to a cookie, but doesn't actually have anything to do with cookies on the Web or in your Web browser.
Connect
Lots of classes in this inheritance column have methods named Connect, Close, and OnRun. They are labeled virtual void, which means inheriting classes will override them, and they return nothing. And, they all call each other. Here's the summary for Connect:
CNeighboursBase::Connect does nothing CNeighboursWithG1::Connect calls CNeighboursBase::Connect and then m_pPingRoute->SetDuration CNeighboursWithG2::Connect calls CNeighboursWithG1::Connect and then HubHorizonPool.Setup CNeighbours::Connect calls CNeighboursWithConnect::Connect, which doesn't exist, and leads to CNeighboursWithG2::Connect.
So, CNeighboursWithG1::Connect sets the ping route duration, and CNeighboursWithG2::Connect sets the ping route duration and sets up the hub horizon pool. Of course, I have no idea what either of these things are yet.
Here is the code for CNeighbours::Connect. Since Shareaza only makes CNeighbours objects, this is the method that will get called externally.
<source lang="c"> void CNeighbours::Connect() { CNeighboursWithConnect::Connect(); } </source>
All it does it pass control to the Connect method in CNeighboursWithConnect. But there is no Connect method in CNeighboursWithConnect. To see where control passes, I'll set a breakpoint. It goes to the highest Connect method in the inheritance chain, which in this case is CNeighboursWithG2::Connect.
Close
Another method that appears several places in the column is Close. It appears in:
CNeighboursBase CNeighbours CNeighboursWithG1
Here's what the Close method in each class does:
CNeighboursBase calls Close on each neighbour in the list, and resets member variables back to 0 CNeighbours calls CNeighboursWithConnect, which doesn't exist, and leads to CNeighboursWithG1. This is the same thing that happs with Connect. CNeighboursWithG1 calls CNeighboursBase and then clears the ping and pong route caches.
So, CNeighboursBase calls Close on each neighbour in the list, and resets member variables. CNeighboursWithG1 does all that and then clears the ping and pong route caches. Calling Close on the CNeighbours object leads to that, which does everything.
Note that control passes to CNeighboursWithG2 for Connect and CNeighboursWithG1 for Close. This isn't because any remote computer is running Gnutella or Gnutella2 software. The method that gets called is the next highest method in the inheritance column with the given name. For Connect, it's always CNeighboursWithG2. For Close, it's always CNeighboursWithG1.
OnRun
Hopefully the last method like this here is OnRun. It's defined in:
CNeighbours CNeighboursWithConnect CNeighboursBase
The WithConnect method calls WithRouting, which doesn't exist, and leads to CNeighboursBase. Here's what they do:
CNeighbours just calls CNeighboursWithConnect CNeighboursWithConnect calls CNeighboursBase, and then maintains the network auto connection CNeighboursBase calls DoRun on each neighbour in the list, making them transfer data
So, CNeighbours and CNeighboursWithConnect do everything, which involves calling DoRun on each neighbour in the list, and then maintaining the network auto connection. CNeighboursBase just runs the neighbours in the list.