예제 #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
bool
Connection::InitWithJoin()
{
	/*
	Send JOIN packet.
	*/
	Packet snd = GenPacket_Join(Network::Instance()->rsaPub);
	if (!Send(snd))
	{
	   LogError(wxString().Format(wxT("Send failed when trying to join on con id %d"),id_));
		return FALSE;
	}

	/*
	Receive JOIN_RESPONSE packet.
	*/
	Packet* rcv;
	if (!Receive(rcv) || rcv == 0)
	{
	   LogError(wxString().Format(wxT("Receive failed when trying to join on con id %d"), id_));
		return FALSE;
	}

	switch(rcv->Type())
	{
	case Packet::TYPE_JOIN_RESPONSE:
	{
		currentAddr_ = rcv->Get(Packet::HEADER_SRC_ADDR);
		currentNid_ = rcv->Get(Packet::HEADER_SRC_NID);

		wxString assign = rcv->Get(Packet::HEADER_ASSIGN_NID);

		wxString address = rcv->Get(Packet::HEADER_NODE);
		wxString nid = rcv->Get(Packet::HEADER_NID);

		Network::Instance()->SetGateway(rcv->Get(Packet::HEADER_DEST_HOST));

		delete rcv;

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

		if (assign == wxT(""))
		{
		   LogError(wxString().Format(wxT("Join response included a blank assign nid on con id %d"),id_));
			return FALSE;
		}

		Prefs::Instance()->Set(Prefs::NID,assign);

		LogDebug(wxString().Format(wxT("Found parent: %s (%s) on con id %d"),nid.c_str(),address.c_str(), id_));

		/*
		We found our new parent, so say hello.
		*/
		if (!HelloParent(Node(nid,address)))
		{
			PostConEvent(EVENT_NEXT_LOST);
			return FALSE;
		}
		else
		{
			PostConEvent(EVENT_NEXT_CONNECTED);
		}

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

	/*
	Lets save this node in the finger table.
	*/
	Network::Instance()->finger.Add(Node(currentNid_,currentAddr_));
	Prefs::Instance()->GetHostCache()->AddHost(currentAddr_);

	return TRUE;
}
예제 #4
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;
}
예제 #5
0
void Connection::HandleImEvents(ImEventQueue* queue)
{
	ImEvent* event;

	while(true/*!(Network::Instance()->KillAll())*/)
	{
		// see if there are any events to send
		event = queue->PopSendEvent();
		if (event != (ImEvent*)0)
		{
			switch (event->type)
			{
			case ImEvent::EVENT_IM:
			{
				Packet snd = GenPacket_Im(event->data);
				if (!Send(snd))
				{
				   LogError(wxString().Format(wxT("Sending im %s on con id %d"),event->data.c_str(),id_));
					PostConEvent(ImEvent::EVENT_LOST);
					delete event;
					return;
				}

				PostConEvent(ImEvent::EVENT_SENT);

				break;
			}
			case ImEvent::EVENT_CLOSE:
			{
				Packet snd = GenPacket_ImClose();
				if (!Send(snd))
				{
				   LogDebug(wxString().Format(wxT("Sending close im event on con id %d"),id_));
					PostConEvent(ImEvent::EVENT_LOST);
					delete event ;
					return;
				}

				break;
			}
			case ImEvent::EVENT_DISCONNECT:
			{
				PostConEvent(ImEvent::EVENT_LOST);
				delete event;
				return;

				break;
			}
			}

			delete event;
		}

		// see if there are any packets to read
		if (socket_->ReadReady())
		{
			Packet* rcv;
			if (Receive(rcv/*,FALSE*/))
			{
				if (rcv != (Packet*)0)
				{
					switch (rcv->Type())
					{
					case Packet::TYPE_IM_CLOSED:
					{
						PostConEvent(ImEvent::EVENT_CLOSE);
						break;
					}
					case Packet::TYPE_IM:
					{
						event = new ImEvent(ImEvent::EVENT_IM,rcv->Get(Packet::HEADER_IM));
						PostConEvent(ImEvent::EVENT_IM,event);
						break;
					}
					}
				}
			}
			else
			{
				PostConEvent(ImEvent::EVENT_LOST);
				return;
			}
		}

		wxThread::Sleep(1);
	}

	PostConEvent(ImEvent::EVENT_LOST);
}
예제 #6
0
// this function does not send events
bool
Connection::InitWithHandshake()
{
	/*
	Send the SYN packet.
	*/
	Packet snd = GenPacket_Syn(Network::Instance()->rsaPub);
	if (!Send(snd))
	{
	   LogError(wxString().Format(wxT("Send failed when trying to handshake on con id %d"),id_));
		return FALSE;
	}
	
	/*
	Get the ACK packet.
	*/
	Packet* rcv;
	if (!Receive(rcv) || rcv == 0)
	{
	   LogError(wxString().Format(wxT("Receive failed when trying to handshake on con id %d"), id_));
		return FALSE;
	}

	switch(rcv->Type())
	{
	case Packet::TYPE_ACK:
	{
		// this is the address and nid of the host we are working with, if
		//currentAddr_ = rcv->Get(Packet::HEADER_SRC_ADDR);
	   currentAddr_ = wxString().Format(wxT("%s/%d"),socket_->GetPeerHost().c_str(),ParsePort(rcv->Get(Packet::HEADER_SRC_ADDR)));
		currentNid_ = rcv->Get(Packet::HEADER_SRC_NID);

#ifdef ENABLE_ENCRYPTION
		wxString key = rcv->Get(Packet::HEADER_SYMETRIC_KEY);
		symetric_->Init(key.c_str()/*,(unsigned char*)"blah"*/);
#endif

		Network::Instance()->SetGateway(rcv->Get(Packet::HEADER_DEST_HOST));

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

		Packet snd = GenPacket_Confirm(wxString(socket_->GetPeerHost().c_str()));
		if (!Send(snd))
		{
		   LogError(wxString().Format(wxT("Send failed when trying to handshake on con id %d"),id_));
			return FALSE;
		}

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

	/*
	Lets store this node in the finger table and heck, even the hostcache.
	*/
	Network::Instance()->finger.Add(Node(currentNid_,currentAddr_));
	Prefs::Instance()->GetHostCache()->AddHost(currentAddr_);

	delete rcv;

	return TRUE;
}
예제 #7
0
void
Connection::Put(ShareFile* file)
{
	char buffer[FILE_SEG_BUFFER_SIZE+1];
	// the total bytes transfered in this session
	unsigned int totalBytesTransfered = 0;

	LogMsg(wxString().Format(wxT("Uploading file %s ..."),file->Path().c_str()));

	Network::Instance()->AddUpload(file);

	wxFile data(file->Path(), wxFile::read);

	if (!data.IsOpened())
	{
	   LogError(wxT("Failed to open file for reading to upload."));
		file->Status(ShareFile::STATUS_FAILED);
		data.Close();
		return;
	}

	file->Status(ShareFile::STATUS_INPROGRESS);

	memset(buffer, 0, sizeof(*buffer));

	sw_->Start(0);

	while (true)
	{

		if (Network::Instance()->KillAll() ||
			file->Status() == ShareFile::STATUS_CANCELLED)
		{
		   LogDebug(wxT("File transfer thread got signal to exit"));
			file->Status(ShareFile::STATUS_PAUSED);
			data.Close();
			return;
		}

		unsigned int start = 0;
		unsigned int end = 0;

		/*
		Remember, this session does not mean we are transfering a file.  The
		remote host can request any file segment as long as it is from the
		same file requested in any order he wants.  So if he drops the
		connection then he's done asking.
		*/
		Packet* rcv;
		if (!Receive(rcv) || rcv == 0)
		{
			file->Status(ShareFile::STATUS_FINISHED);
			data.Close();
			delete rcv;
			return;
		}

		switch(rcv->Type())
		{
		case Packet::TYPE_CONT:
		{
			wxString startTxt = rcv->Get(Packet::HEADER_FILESEG_START);
			wxString endTxt = rcv->Get(Packet::HEADER_FILESEG_END);
			start = atoi(startTxt.c_str());
			end = atoi(endTxt.c_str());

			if (start < 0 || start >= end || end > file->Size()
				||
			    startTxt == wxT("") || endTxt == wxT("")
				|| end-start > FILE_SEG_BUFFER_SIZE)
			{
			   LogError(wxString().Format(wxT("Invalid start %d or end %d range requested on con id %d"),start,end,id_));
				file->Status(ShareFile::STATUS_FAILED);
				data.Close();
				delete rcv;
				return;
			}
			break;
		}
		default:
		   LogError(wxString().Format(wxT("Did not receive CONT packet when expected on con id %d"), id_));
		}

		if (data.Seek(start, wxFromStart) != start)
		{
			file->Status(ShareFile::STATUS_FAILED);
			data.Close();
			LogError(wxString().Format(wxT("Could not seek to requested file byte: %d"),start));
			return;
		}

		delete rcv;

		unsigned int count = data.Read(buffer,end-start);

		if (count != end-start)
		{
		   LogError(wxString().Format(wxT("Could not read requested file segment from local file on con id %d"),id_));
			file->Status(ShareFile::STATUS_FAILED);
			return;
		}

		//LogDebug(wxString().Format("Sending %d (%d) bytes ...",end-start,strlen(buffer)));

		Packet snd = GenPacket_Send(buffer,count);
		if (!Send(snd))
		{
		   LogError(wxString().Format(wxT("Failed when sending file on con id %d"),id_));
			file->Status(ShareFile::STATUS_FAILED);
			return;
		}

		totalBytesTransfered += count;
		file->CompletedSize(totalBytesTransfered);

		file->Kbs((double)(totalBytesTransfered/1024)/(double)(sw_->Time()/1000));
	}
}
예제 #8
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);
	}
}
예제 #9
0
void
FileTransferThread::Get(ShareFile& file)
{
	// save the info file (recovery file) every this count of packets
	const int SAVE_INFO_FILE_EVERY = 10;
	// counter for when to save info file
	int saveInfoFile = 0;
	// the total bytes read in THIS session
	unsigned int totalBytesTransfered = 0;

	LogMsg(wxString().Format("Downloading file %s ...",file.Path().c_str()));

	if (!Connect())
	{
		LogError(wxString().Format("Handshaking failed when starting file transfer in con id %d",id_));
		file.Status(ShareFile::STATUS_FAILED);
		return;
	}

	/*
	Send the request for the file segment.
	*/
	Packet snd = GenPacket_Request(file.Name(),file.MD5());
	if (!Send(snd))
	{
		LogError(wxString().Format("Failed when requesting file on con id %d",id_));
		file.Status(ShareFile::STATUS_FAILED);
		return;
	}

	wxFile data(file.PartPath(), wxFile::write);

	if (!data.IsOpened())
	{
		LogMsg(wxString().Format("Failed to open download file %s for writing",file.Path().c_str()));
		file.Status(ShareFile::STATUS_FAILED);
		data.Close();
		return;
	}

	if (!file.LoadInfoFile())
	{
		file.Status(ShareFile::STATUS_FAILED);
		data.Close();
		LogError("Corrupt info file.");
		return;
	}

	// seek to where we left off
	if (data.Seek(file.CompletedSize(), wxFromStart) != file.CompletedSize())
	{
		file.Status(ShareFile::STATUS_FAILED);
		data.Close();
		LogError("Info file and part file do not match.");
		return;
	}

	file.Status(ShareFile::STATUS_INPROGRESS);

	sw_->Start(0);
	bool first = true;

	while (true)
	{
		if (Network::Instance()->KillAll() ||
			file.Status() == ShareFile::STATUS_CANCELLED ||
			file.Status() == ShareFile::STATUS_PAUSED)
		{
			//LogDebug("File transfer thread got signal to exit");
			file.Status(ShareFile::STATUS_PAUSED);
			data.Close();
			return;
		}
		else if (file.Size() == file.CompletedSize())
		{
			LogMsg(wxString().Format("Download of file %s completed.",file.Path().c_str()));
			file.Status(ShareFile::STATUS_FINISHED);

			file.PartToReal();

			if (crypto::Md5Hash(file.Path()) != file.MD5())
			{
				LogError("MD5's don't match!  File is corrupt.");
				file.MD5(file.MD5() + " (Downloaded file does not match MD5)");
				file.Status(ShareFile::STATUS_FAILED);
			}

			data.Close();
			return;
		}
		else if (file.Size() < file.CompletedSize())
		{
			LogError("Got too many bytes in file!");
			file.Status(ShareFile::STATUS_FAILED);
			data.Close();
			return;
		}

		unsigned int end;

		if (first)
		{
			first = false;
			/*
			Request the next file segment we need with a start and ending byte.
			*/
			end = file.CompletedSize() + FILE_SEG_BUFFER_SIZE;
			if (end > file.Size())
				end = file.Size();

			Packet snd = GenPacket_Cont(file.CompletedSize(),end);
			if (!Send(snd))
			{
				LogError(wxString().Format("Failed when sending cont on con id %d",id_));
				file.Status(ShareFile::STATUS_FAILED);
				return;
			}
		}

		/*
		Get the data.
		*/
		Packet* rcv;
		if (!Receive(rcv) || rcv == 0)
		{
			LogError(wxString().Format("Receive failed when trying to get file packet on con id %d", id_));
			file.Status(ShareFile::STATUS_FAILED);
			data.Close();
			delete rcv;
			return;
		}

		if (!rcv->Valid())
		{
			LogError(wxString().Format("Receive invalid packet when trying to get file packet on con id %d", id_));
			file.Status(ShareFile::STATUS_FAILED);
			data.Close();
			delete rcv;
			return;
		}

		/*
		Request the next file segment we need with a start and ending byte.
		*/
		if (file.Size() > end)
		{
			unsigned int start = end;
			end += FILE_SEG_BUFFER_SIZE;
			if (end > file.Size())
				end = file.Size();

			Packet snd = GenPacket_Cont(start,end);
			if (!Send(snd))
			{
				LogError(wxString().Format("Failed when sending cont on con id %d",id_));
				file.Status(ShareFile::STATUS_FAILED);
				return;
			}
		}

		switch(rcv->Type())
		{
		case Packet::TYPE_FILESEG:
		{
			string raw = crypto::HexDecode(rcv->Get(Packet::HEADER_PAYLOAD).c_str());
			unsigned int count = data.Write(raw.c_str(), raw.size());

			//LogDebug(wxString().Format("Received %d (%d) bytes ...",rcv->Get(Packet::HEADER_PAYLOAD).size(),count));

			// make sure the write was successful
			if (count != raw.size())
			{
				LogError(wxString().Format("Failed to write to file (disk may be full) on con id %d", id_));
				file.Status(ShareFile::STATUS_FAILED);
				data.Close();
				delete rcv;
				return;
			}

			file.CompletedSize(file.CompletedSize()+count);
			totalBytesTransfered += count;
			file.Kbs((double)(totalBytesTransfered/1024)/(double)(sw_->Time()/1000));

			++saveInfoFile;

			if (saveInfoFile == SAVE_INFO_FILE_EVERY)
			{
				saveInfoFile = 0;
				//file.SaveInfoFile();
			}

			break;
		}
		default:
		{
			delete rcv;
			data.Close();
			LogError(wxString().Format("Receive bad packet type when trying to get file packet on con id %d", id_));
			file.Status(ShareFile::STATUS_FAILED);
			return;
		}
		}

		delete rcv;
	}
}