예제 #1
0
bool
Connection::JoinParent()
{
	if (!Connect())
	{
	   LogError(wxString().Format(wxT(" Handshake failed in con id %d"),id_));
		KillSocket(-1);
		return FALSE;
	}

	/*
	Tell our parent hello and it has just born a new child.
	*/
	Packet packet = GenPacket_HelloNext();
	if (!Send(packet))
	{
	   LogError(wxString().Format(wxT(" Send failed in con id %d when trying to say hello to parent"),id_));
		KillSocket(-1);
		return FALSE;
	}

	/*
	Receive all the hashes we are responsible for.
	*/
	Packet* rcv;
	if (!Receive(rcv) || rcv == 0)
	{
	   LogError(wxString().Format(wxT(" Receive failed when getting responsible hashes from parent on con id %d"), id_));
		KillSocket(-1);
		return FALSE;
	}

	KillSocket(-1);

	// add all the hashes we are responsible for to our hash table
	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));
	}

	delete rcv;

	return TRUE;
}
예제 #2
0
LookupResponse
Connection::DirectQuery(wxString key)
{
	LookupResponse answer(LookupResponse::FAIL);

 	if (!Connect())
	{
	   LogError(wxString().Format(wxT("Connect() failed when doing a direct query in con id %d"),id_));
		KillSocket(-1);
		return answer;
	}

	/*
	Send QUERY.
	*/
	Packet snd = GenPacket_Query(key);
	if (!Send(snd))
	{
	   LogError(wxString().Format(wxT("Send failed when trying to direct query on con id %d"),id_));
		KillSocket(-1);
		return answer;
	}

	/*
	Receive some sort of query response.
	*/
	Packet* rcv;
	if (!Receive(rcv) || rcv == 0)
	{
	   LogError(wxString().Format(wxT("Receive failed when trying to direct query on con id %d"), id_));
		KillSocket(-1);
		return answer;
	}

	KillSocket(-1);

	switch(rcv->Type())
	{
	case Packet::TYPE_RESPONSE_FOUND:
	{
		answer = LookupResponse(LookupResponse::FOUND,Node(currentNid_,currentAddr_));

		for (int x = 0; x < rcv->Count(Packet::HEADER_NODE);x++)
		{
			wxString node = rcv->Get(Packet::HEADER_NODE,x);
			wxString info = rcv->Get(Packet::HEADER_INFO,x);
			answer.AddResponse(HashValue(node,key,info));
		}

		break;
	}
	case Packet::TYPE_RESPONSE_JUMP:
	{
	   answer = LookupResponse(LookupResponse::JUMP,Node(wxT("UNDEFINED"),rcv->Get(Packet::HEADER_JUMP)));
		break;
	}
	case Packet::TYPE_RESPONSE_SUCCESSOR:
	{
		answer = LookupResponse(LookupResponse::SUCCESSOR,Node(currentNid_,currentAddr_));
		break;
	}
	default:
	{
	   LogError(wxString().Format(wxT("Received an invalid lookup response from node on con id %d"), id_));
		break;
	}
	}

	delete rcv;
	return answer;
}
예제 #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;
}