Exemplo n.º 1
0
bool
Connection::HelloParent(const Node& node)
{
	Network::Instance()->Join(FALSE);

	Connection* helloNextCon = new Connection(0,-1,TYPE_MANUAL,node.Address());
	if (!helloNextCon->JoinParent())
	{
		delete helloNextCon;
		LogError(wxString().Format(wxT("Could not contact successor node %s"),node.Address().c_str()));
		return FALSE;
	}

	delete helloNextCon;

	/*
	Add first next.
	*/
	Network::Instance()->ClearNext();
	Network::Instance()->AddNext(node);

	/*
	Allow nodes to officially connect to me now.
	*/
	Network::Instance()->Join(TRUE);

	return TRUE;
}
Exemplo n.º 2
0
	void NeighbourList::Add( const Node& neighbour )
	{
		for( 	std::vector< std::pair< RDTimeStamp, Node> >::iterator i = m_neighbours.begin();
			i != m_neighbours.end(); ++i )
		{
			if( i->second == neighbour )
			{
				i->second = neighbour;
				i->first = Logger::Time();
				return;
			}
		}
		
		std::pair< RDTimeStamp, Node > p( Logger::Time(), neighbour );
		m_neighbours.push_back( p );
		
		RD_NLOG( "Adding New Neighbour: Node " << neighbour.Address() );
		
		m_delegate.OnNeighbourAdded( *this, neighbour );
	}
Exemplo n.º 3
0
// this function does not send events
bool
Connection::ReceiveHandShake()
{
	// TODO check the banned list!

	/*
	Get the SYN or JOIN packet.
	*/
	Packet* rcv;
	if (!Receive(rcv) || rcv == 0)
	{
	   LogError(wxString().Format(wxT("Receive failed on incomming con id %d"), id_));
		return FALSE;
	}

	switch(rcv->Type())
	{
	// node is a network node and wants to handshake
	case Packet::TYPE_SYN:
	{

#ifdef ENABLE_ENCRYPTION
		rsaPub_ = rcv->Get(Packet::HEADER_PUBLIC_KEY);

		if (rsaPub_ == wxT(""))
		{
		   LogError(wxString().Format(wxT("Got empty RSA public key on incomming con id %d"), id_));
			return false;
		}
#endif

		delete rcv;

#ifdef ENABLE_ENCRYPTION
		/*
		Init encryption.
		*/
		symetric_->Init(crypto::RandomString().c_str()/*,(unsigned char*)"blah"*/);
#endif
		/*
		Send the ACK packet.
		*/
#ifdef ENABLE_ENCRYPTION
		Packet snd = GenPacket_Ack(wxString(symetric_->Key().c_str()),wxString(socket_->GetPeerHost().c_str()));
#else
		Packet snd = GenPacket_Ack(wxString(),wxString(socket_->GetPeerHost().c_str()));
#endif
		if (!Send(snd))
		{
		   LogError(wxString().Format(wxT("ACK send failed on incomming con id %d"),id_));
			return FALSE;
		}

		if (!Receive(rcv) || rcv == 0)
		{
		   LogError(wxString().Format(wxT("Receive confirm packet failed on incomming con id %d"), id_));
			return FALSE;
		}

		if (rcv->Type() != Packet::TYPE_CONFIRM)
		{
		   LogError(wxString().Format(wxT("Did not get confirm packet on incomming con id %d, got packet type %d instead"), id_,rcv->Type()));
			return FALSE;
		}

		// TODO get the correct hostname if none is supplied
		currentAddr_ = rcv->Get(Packet::HEADER_SRC_ADDR);

		currentNid_ = rcv->Get(Packet::HEADER_SRC_NID);
		wxString wrkGrpKey = rcv->Get(Packet::HEADER_WRKGRPKEY);
		Network::Instance()->SetGateway(rcv->Get(Packet::HEADER_DEST_HOST));

		if (Prefs::Instance()->Get(Prefs::WRKGRPKEY) != wxT("")
			&&
			wrkGrpKey != Prefs::Instance()->Get(Prefs::WRKGRPKEY))
		{
		   LogError(wxString().Format(wxT("Node tried to connect with invalid workgroup %s key on incomming con id %d packet: %s"), wrkGrpKey.c_str(),id_,rcv->Raw()));
			delete rcv;
			return FALSE;
		}


		if (currentAddr_ == wxT("") || currentNid_ == wxT(""))
		{
		   LogError(wxString().Format(wxT("(3) Blank address or nid from node when trying to handshake on con id %d"),id_));
			delete rcv;
			return FALSE;
		}

		delete rcv;

		/*
		Now that handshaking is out of the way, lets figure out what this node wants.
		*/
		if (!Receive(rcv) || rcv == 0)
		{
		   LogError(wxString().Format(wxT("Receive failed on incomming con id %d"), id_));
			return FALSE;
		}

		switch(rcv->Type())
		{
		case Packet::TYPE_QUERY:
		{
			// get the hash we are being queried for
			wxString hash = rcv->Get(Packet::HEADER_HASH);

			LogDebug(wxString().Format(wxT("Responding to a query for '%s' on incomming con id %d"),hash.c_str(),id_));

			delete rcv;

			if (Network::Instance()->IsSuccessor(Prefs::Instance()->Get(Prefs::NID),
				Network::Instance()->Prev().Nid(),hash))
			{
				Packet answer = GenPacket_ResponseSuccess();
				bool found = FALSE;
				HashValue value;
				for (int x = 1; ;x++)
				{
					value = Network::Instance()->hashTable->GetNext(hash,x);

					if (value.hash == wxT(""))
						break;

					// responsible node information
					answer.Add(Packet::HEADER_NODE, value.node);
					answer.Add(Packet::HEADER_INFO, value.info);

					// yes, we are responsible for this mess
					found = TRUE;
				}

				if (found)	// we are responsible for the hash and we have it
				{
				   LogDebug(wxString().Format(wxT("We have the hash %s"),hash.c_str()));

					if (!Send(answer))
					{
						return FALSE;
					}
				}
				else	// we are responsible for the hash but don't have it
				{
				   LogDebug(wxString().Format(wxT("We have no entry matching hash %s"),hash.c_str()));

					Packet snd = GenPacket_ResponseEnd();
					if (!Send(snd))
					{
					   LogError(wxString().Format(wxT(" Send failed on incomming con id %d"),id_));
						return FALSE;
					}
				}
			}
			else	// not resposible, so tell them where to jump to next
			{
				// TODO use the finger table to find a jump node
				Node next;
				if (!Network::Instance()->GetNext(0,next))
				{
				   LogError(wxT("Could not get next to generate jump packet."));
				}

				Packet snd = GenPacket_ResponseJump(next.Address());
				if (!Send(snd))
				{
				   LogError(wxString().Format(wxT(" Send jump failed on incomming con id %d"),id_));
					return FALSE;
				}
			}

			break;
		}
		case Packet::TYPE_HELLO_NEXT:
		{
			delete rcv;

			LogDebug(wxString().Format(wxT("Got a hello next from %s"),currentNid_.c_str()));

			bool dojoin = FALSE;
			//if (Network::Instance()->Prev().Nid() == wxT("") &&
			//		Network::Instance()->seed_)
			Node next;
			Network::Instance()->GetNext(0,next);
			if (next.Nid() == Prefs::Instance()->Get(Prefs::NID))
			{
				dojoin = TRUE;
			}

			/*
			We now have a new previous!
			*/
			Network::Instance()->Prev(Node(currentNid_,currentAddr_));

			// TODO do a lookup and make sure we are the real successor!

			/*
			A new node just said it is my new child, so I have to:
			- send it all the hashes < than the new node's nid
			*/
			Packet insert = GenPacket_Insert();
			HashValue value;
			//bool found = FALSE;
			for (unsigned int x = 1;;++x)
			{
				value = Network::Instance()->hashTable->Get(x);

				if (value.hash == wxT(""))
					break;

				if (!Network::Instance()->IsSuccessor(Prefs::Instance()->Get(Prefs::NID),
					Network::Instance()->Prev().Nid(),value.hash))
				{

				   LogDebug(wxString().Format(wxT("Giving up hash %s to prev %s"),value.hash.c_str(),currentNid_.c_str()));

					insert.Add(Packet::HEADER_HASH,value.hash);
					insert.Add(Packet::HEADER_NODE,value.node);
					insert.Add(Packet::HEADER_INFO,value.info);
				}
				//found = TRUE;
			}

			// send an insert even if we have no hashes, this means "OK"
			if (!Send(insert))
			{
			   LogError(wxString().Format(wxT("Send insert failed on incomming con id %d"),id_));
				return FALSE;
			}

			/*
			If we don't have a next pointer then use the first new child (this will happen if
			we are a seed)
			*/
			if (dojoin)
			{
			   LogDebug(wxString().Format(wxT("Seed node, so joining parent %s"),currentNid_.c_str()));

				/*
				Now that we have a next pointer, lets say hey to it.
				*/
				if (!HelloParent(Node(currentNid_,currentAddr_)))
				{
					// if we can't connect to the node that just connected to us we lost our next
					PostConEvent(EVENT_NEXT_LOST);
					return FALSE;
				}
				else
				{
					//PostConEvent(EVENT_NEXT_CONNECTED);
				}
			}

			PostConEvent(EVENT_PREV_CONNECTED);

			break;
		}
		case Packet::TYPE_STAT:
		{
			delete rcv;

			Packet snd = GenPacket_StatResponse();
			if (!Send(snd))
			{
			   LogError(wxString().Format(wxT("STAT_RESPONSE send failed on incomming con id %d"),id_));
				return FALSE;
			}
			break;
		}
		case Packet::TYPE_REQUEST:
		{
			/*
			Client is requesting a file we have.
			... No need to check if we have the file or not here, the filetransferthread
			will fail if we don't have the file.
			*/

			// get the filename and an md5 of the file requested
			wxString md5 = rcv->Get(Packet::HEADER_FILEMD5);
			wxString filename = rcv->Get(Packet::HEADER_FILENAME);

			delete rcv;

			if (currentAddr_ == wxT("") || currentNid_ == wxT(""))
			{
			   LogError(wxString().Format(wxT("(4) Blank address or nid from node when trying to handshake on con id %d"),id_));
				delete rcv;
				return FALSE;
			}

			bool found = FALSE;
			for (unsigned int x = 0; x < Prefs::Instance()->sharedFiles.size();x++)
			{
				if (Prefs::Instance()->sharedFiles[x].Name() == filename &&
					Prefs::Instance()->sharedFiles[x].MD5() == md5)
				{
				   LogDebug(wxString().Format(wxT("Sending file %s with MD5 %s on incomming con id %d"), filename.c_str(),md5.c_str(),id_));
					ShareFile* file = new ShareFile(Prefs::Instance()->sharedFiles[x]);
					Put(file);
					found = TRUE;
					break;
				}
			}

			if (!found)
			{
			   LogError(wxString().Format(wxT(" Don't have request for file %s with MD5 %s on incomming con id %d"), filename.c_str(),md5.c_str(),id_));
				return FALSE;
			}

			break;
		}
		case Packet::TYPE_HELLO_BUDDY:
		{
			/*
			A buddy has signed on and is now saying hello to us.
			Set his status to online and save some info about him.
			*/
			wxString info = rcv->Get(Packet::HEADER_INFO);

			delete rcv;

			Buddy* buddy = 0;

			wxStringTokenizer tokens(info, wxT(":"));
			// TODO make sure the buddy info is valid (we have all the tokens)
			if (tokens.GetNextToken() == wxT("BUDDY"))
			{
				wxMutexGuiEnter();

				BuddyTreeCtrl* tree = wxGetApp().GetMainWindow()->GetTreeCtrl();
				wxString alias = tokens.GetNextToken();
				wxString publicKey = tokens.GetNextToken();
				wxString profile = tokens.GetNextToken();
				tree->SetBuddyData(publicKey, alias, profile, currentAddr_);

				buddy = tree->GetBuddy(publicKey);
				if (buddy != 0)
					buddy->SetStatusOn(Buddy::STATUS_ONLINE);

				wxMutexGuiLeave();

				LogMsg(wxString().Format(wxT("Found that buddy '%s' with id '%s' is online."),alias.c_str(),publicKey.c_str()));
			}
			else
			{
			   LogError(wxT("Got an invalid info header on buddy hello."));
			}

			break;
		}
		case Packet::TYPE_IM_CONNECT:
		{
			/*
			A buddy wants to connect to us.
			*/
			wxString info = rcv->Get(Packet::HEADER_INFO);

			delete rcv;

			Buddy* buddy = 0;

			wxStringTokenizer tokens(info, wxT(":"));
			// TODO make sure the buddy info is valid (we have all the tokens)
			if (tokens.GetNextToken() == wxT("BUDDY"))
			{
				wxString alias = tokens.GetNextToken();
				wxString publicKey = tokens.GetNextToken();
				wxString profile = tokens.GetNextToken();

				wxMutexGuiEnter();

				BuddyTreeCtrl* tree = wxGetApp().GetMainWindow()->GetTreeCtrl();
				buddy = tree->GetBuddy(publicKey);
				if (buddy != 0)
				{
					tree->SetBuddyData(publicKey, alias, profile, currentAddr_);

					LogMsg(wxString().Format(wxT("Buddy '%s' with id '%s' wants to connect."),alias.c_str(),publicKey.c_str()));
					//buddy->SetStatusOn(Buddy::STATUS_ONLINE);
				}
				else
				{
				   wxMessageDialog diag(0,wxT("Buddy '")+ alias + wxT("' wants to make an instant message connection to you. Do you want to accept this connection and add this buddy to your list?"),wxT("New Buddy Connection"),wxYES|wxNO);
					if (diag.ShowModal() == wxYES)
					{
					}
				}
				wxMutexGuiLeave();
			}
			else
			{
			   LogError(wxT("Got an invalid info header on buddy hello."));
			}

			if (buddy != 0)
			{
				parent_ = buddy;
				parentId_ = buddy->id();

				ImEventQueue* queue = new ImEventQueue();

				PostConEvent(ImEvent::EVENT_MADE,(void*)queue);

				/*
				Process the IM events.
				*/
				HandleImEvents(queue);

				PostConEvent(ImEvent::EVENT_LOST);

				//delete queue;
			}

			break;
		}
		case Packet::TYPE_INSERT:
		{
			// somebody wants to give us some hashes to be responsible for
			// TODO we should validate if we are responsible for them or not
			for (int x = 0; x < rcv->Count(Packet::HEADER_HASH); x++)
			{
				wxString hash = rcv->Get(Packet::HEADER_HASH,x);
				wxString node = rcv->Get(Packet::HEADER_NODE,x);
				wxString info = rcv->Get(Packet::HEADER_INFO,x);
				Network::Instance()->hashTable->Add(HashValue(node,hash,info));
				
				LogDebug(wxString().Format(wxT("Now responsible for hash: %s with owner %s and info %s"), hash.c_str(),node.c_str(),info.c_str()));
			}

			delete rcv;

			break;
		}
		default:
		{
		   LogError(wxString().Format(wxT("Invalid packet on incomming con id %d"), id_));
			delete rcv;
			return FALSE;
		}
		}

		break;
	}
	// node is not a network node and wants to join
	case Packet::TYPE_JOIN:
	{
		//currentAddr_ = rcv->Get(Packet::HEADER_SRC_ADDR);
	   currentAddr_ = wxString().Format(wxT("%s/%d"),socket_->GetPeerHost().c_str(),ParsePort(rcv->Get(Packet::HEADER_SRC_ADDR)));
		rsaPub_ = rcv->Get(Packet::HEADER_PUBLIC_KEY);
		wxString wrkGrpKey = rcv->Get(Packet::HEADER_WRKGRPKEY);

		if (Prefs::Instance()->Get(Prefs::WRKGRPKEY) != wxT("")
			&&
			wrkGrpKey != Prefs::Instance()->Get(Prefs::WRKGRPKEY))
		{
		   LogError(wxString().Format(wxT(" Node tried to connect with invalid workgroup %s key on incomming con id %d packet: %s"), wrkGrpKey.c_str(),id_,rcv->Raw()));
			delete rcv;
			return FALSE;
		}

		// compute an NID for the new node
		currentNid_ = Network::Instance()->ComputeNid(currentAddr_);

		delete rcv;

		if (currentAddr_ == wxT(""))
		{
		   LogError(wxString().Format(wxT("(5) Blank address or nid from node when trying to handshake on con id %d"),id_));
			delete rcv;
			return FALSE;
		}
#ifdef DEBUG
		// make sure the nid we computed is valid
		if (currentNid_.size() != 40)
		{
			// this should never happen, but whatever
		   LogError(wxT("Computed am invalid blank nid for joining node."));
			return FALSE;
		}
#endif
		/*
		Now, we need to do a lookup and find the parent of the node.
		*/
		LookupResponse answer = Lookup(currentNid_);

		switch(answer.type_)
		{
		case LookupResponse::SUCCESSOR:
		case LookupResponse::FOUND:
		{
			/*
			Found your successor.  If we get anything else from the lookup
			it means we can't do it and drop the connection (this should never happen!)
			*/
			Packet snd = GenPacket_JoinResponse(currentNid_,answer.successor,wxString(socket_->GetPeerHost().c_str()));
			if (!Send(snd))
			{
			   LogError(wxString().Format(wxT("JOIN_RESPONSE send failed on incomming con id %d"),id_));
				return FALSE;
			}
			break;
		}
		default:
		{
		   LogError(wxString().Format(wxT("Lookup failed when trying to find parent for new node on incomming con id %d"),id_));
			return FALSE;
		}
		}

		break;
	}
	default:
	{
	   LogError(wxString().Format(wxT("Invalid packet type %d on incomming con id %d"),rcv->Type(), id_));
		delete rcv;
		return FALSE;
	}
	}

	/*
	Save the node in the finger table.
	*/
	Network::Instance()->finger.Add(Node(currentNid_,currentAddr_));

	return TRUE;
}
Exemplo n.º 4
0
LookupResponse
Connection::Lookup(wxString key,wxString target)
{
	// if we were given nothing to start with, then use the finger table
   if (target == wxT(""))
	{
		// TODO uncomment this line to use the finger table
		//target = Network::Instance()->finger.BestStart(key).Address();

		// if the finger table is useless, then just use our next
	   if (target == wxT("") || Network::Instance()->IsMe(target))
		{
			//target = Network::Instance()->SelfAddress();
			Node next;
			Network::Instance()->GetNext(0,next);
			target = next.Address();
		}
	}

	// the only time this will happen is if i am a seed, so use myself
   if (target == wxT(""))
	{
	   LogError(wxT("Target is null for lookup."));
		return LookupResponse(LookupResponse::FAIL);
	}

	wxString firstAddr;

	/*
	Keep sending queries until we get something or fail.
	*/
	while (!Network::Instance()->KillAll())
	{
	   LogDebug(wxString().Format(wxT("Looking up '%s' on hop '%s'"),key.c_str(),target.c_str()));

		if (firstAddr == target)
		{
		   LogError(wxString().Format(wxT("Went in a complete circle during lookup for %s"),key.c_str()));
			return LookupResponse(LookupResponse::FAIL);
		}

		Connection* queryCon = new Connection(0,-1,TYPE_QUERY,target);
		LookupResponse answer = queryCon->DirectQuery(key);

		// save the first node we look at so we don't loop the circle!
		if (firstAddr == wxT(""))
			firstAddr = target;

		switch(answer.type_)
		{
		case LookupResponse::JUMP:
		{
			delete queryCon;
			target = answer.successor.Address();
			break;
		}
		default:
		{
			delete queryCon;
			return answer;
		}
		}
	}

	// this will never be used
	return LookupResponse(LookupResponse::FAIL);
}
Exemplo n.º 5
0
void
Connection::AnalyzeNetwork()
{
	Node next;
	Network::Instance()->GetNext(0,next);
	currentAddr_ = next.Address();
	currentNid_ = next.Nid();

	wxString firstAddr;

	/*
	Keep sending queries until we get something or fail.
	*/
	while (true)
	{
		if (firstAddr == currentAddr_)
			return;

		LogDebug(wxString().Format(wxT(">>Stating node %s (%s)"),currentAddr_.c_str(),currentNid_.c_str()));

		// save the first node we look at so we don't loop the circle!
		if (firstAddr == wxT(""))
			firstAddr = currentAddr_;

		if (!Connect())
		{
		   LogError(wxString().Format(wxT(" Handshaking failed in con id %d"),id_));
			return;
		}

		/*
		Send a stat request so we can get the predecessor.
		*/
		Packet snd = GenPacket_Stat();
		if (!Send(snd))
		{
		   LogError(wxString().Format(wxT(" Send failed when trying to stat on con id %d"),id_));
			return;
		}

		Packet* rcv;
		if (!Receive(rcv) || rcv == 0)
		{
		   LogError(wxString().Format(wxT(" Receive failed when trying to get the stat response on con id %d"), id_));
			delete rcv;
			return;
		}

		wxString prevNid = rcv->Get(Packet::HEADER_PREV_NID);
		wxString prevAddr = rcv->Get(Packet::HEADER_PREV_ADDR);

		currentNid_ = rcv->Get(Packet::HEADER_NEXT_NID);
		currentAddr_ = rcv->Get(Packet::HEADER_NEXT_ADDR);

		LogDebug(wxString().Format(wxT("<- %s (%s)"), prevAddr.c_str(),prevNid.c_str()));
			 LogDebug(wxString().Format(wxT("-> %s (%s)"), currentAddr_.c_str(),currentNid_.c_str()));

		for (int x = 1; ;x++)
		{
			wxString hash = rcv->Get(Packet::HEADER_HASH,x);
			if (hash == wxT(""))
				break;

			LogDebug(wxString().Format(wxT(">>    Hash: %s"), hash.c_str()));
		}

		delete rcv;

		KillSocket(-1);
	}
}