void CMuleUDPSocket::SendPacket(CPacket* packet, uint32 IP, uint16 port, bool bEncrypt, const uint8* pachTargetClientHashORKadID, bool bKad, uint32 nReceiverVerifyKey) { wxCHECK_RET(packet, wxT("Invalid packet.")); /*wxCHECK_RET(port, wxT("Invalid port.")); wxCHECK_RET(IP, wxT("Invalid IP.")); */ if (!port || !IP) { return; } if (!Ok()) { AddDebugLogLineN(logMuleUDP, (m_name + wxT(": Packet discarded, socket not Ok (")) << Uint32_16toStringIP_Port(IP, port) << wxT("): ") << packet->GetPacketSize() << wxT("b")); delete packet; return; } AddDebugLogLineN(logMuleUDP, (m_name + wxT(": Packet queued (")) << Uint32_16toStringIP_Port(IP, port) << wxT("): ") << packet->GetPacketSize() << wxT("b")); UDPPack newpending; newpending.IP = IP; newpending.port = port; newpending.packet = packet; newpending.time = GetTickCount(); newpending.bEncrypt = bEncrypt && (pachTargetClientHashORKadID != NULL || (bKad && nReceiverVerifyKey != 0)) && thePrefs::IsClientCryptLayerSupported(); newpending.bKad = bKad; newpending.nReceiverVerifyKey = nReceiverVerifyKey; if (newpending.bEncrypt && pachTargetClientHashORKadID != NULL) { md4cpy(newpending.pachTargetClientHashORKadID, pachTargetClientHashORKadID); } else { md4clr(newpending.pachTargetClientHashORKadID); } { wxMutexLocker lock(m_mutex); m_queue.push_back(newpending); } theApp->uploadBandwidthThrottler->QueueForSendingControlPacket(this); }
bool CMuleUDPSocket::SendTo(uint8_t *buffer, uint32_t length, uint32_t ip, uint16_t port) { // Just pretend that we sent the packet in order to avoid infinite loops. if (!(m_socket && m_socket->Ok())) { return true; } amuleIPV4Address addr; addr.Hostname(ip); addr.Service(port); // We better clear this flag here, status might have been changed // between the U.B.T. addition and the real sending happening later m_busy = false; bool sent = false; m_socket->SendTo(addr, buffer, length); if (m_socket->Error()) { wxSocketError error = m_socket->LastError(); if (error == wxSOCKET_WOULDBLOCK) { // Socket is busy and can't send this data right now, // so we just return not sent and set the wouldblock // flag so it gets resent when socket is ready. m_busy = true; } else { // An error which we can't handle happended, so we drop // the packet rather than risk entering an infinite loop. AddLogLineN((wxT("WARNING! ") + m_name + wxT(": Packet to ")) << Uint32_16toStringIP_Port(ip, port) << wxT(" discarded due to error (") << error << wxT(") while sending.")); sent = true; } } else { AddDebugLogLineN(logMuleUDP, (m_name + wxT(": Packet sent (")) << Uint32_16toStringIP_Port(ip, port) << wxT("): ") << length << wxT("b")); sent = true; } return sent; }
void CServerWnd::UpdateED2KInfo() { wxListCtrl* ED2KInfoList = CastChild( ID_ED2KINFO, wxListCtrl ); ED2KInfoList->DeleteAllItems(); ED2KInfoList->InsertItem(0, _("eD2k Status:")); if (theApp->IsConnectedED2K()) { ED2KInfoList->SetItem(0, 1, _("Connected")); // Connection data ED2KInfoList->InsertItem(1, _("IP:Port")); ED2KInfoList->SetItem(1, 1, theApp->serverconnect->IsLowID() ? wxString(_("LowID")) : Uint32_16toStringIP_Port( theApp->GetED2KID(), thePrefs::GetPort())); ED2KInfoList->InsertItem(2, _("ID")); // No need to test the server connect, it's already true ED2KInfoList->SetItem(2, 1, CFormat(wxT("%u")) % theApp->GetED2KID()); ED2KInfoList->InsertItem(3, wxEmptyString); if (theApp->serverconnect->IsLowID()) { ED2KInfoList->SetItem(1, 1, _("Server")); // LowID, unknown ip ED2KInfoList->SetItem(3, 1, _("LowID")); } else { ED2KInfoList->SetItem(1, 1, Uint32_16toStringIP_Port(theApp->GetED2KID(), thePrefs::GetPort())); ED2KInfoList->SetItem(3, 1, _("HighID")); } } else { // No data ED2KInfoList->SetItem(0, 1, _("Not Connected")); } // Fit the width of the columns ED2KInfoList->SetColumnWidth(0, -1); ED2KInfoList->SetColumnWidth(1, -1); }
void CDownloadQueue::KademliaSearchFile(uint32_t searchID, const Kademlia::CUInt128* pcontactID, const Kademlia::CUInt128* pbuddyID, uint8_t type, uint32_t ip, uint16_t tcp, uint16_t udp, uint32_t buddyip, uint16_t buddyport, uint8_t byCryptOptions) { AddDebugLogLineN(logKadSearch, CFormat(wxT("Search result sources (type %i)")) % type); //Safety measure to make sure we are looking for these sources CPartFile* temp = GetFileByKadFileSearchID(searchID); if( !temp ) { AddDebugLogLineN(logKadSearch, wxT("This is not the file we're looking for...")); return; } //Do we need more sources? if(!(!temp->IsStopped() && thePrefs::GetMaxSourcePerFile() > temp->GetSourceCount())) { AddDebugLogLineN(logKadSearch, wxT("No more sources needed for this file")); return; } uint32_t ED2KID = wxUINT32_SWAP_ALWAYS(ip); if (theApp->ipfilter->IsFiltered(ED2KID)) { AddDebugLogLineN(logKadSearch, wxT("Source ip got filtered")); AddDebugLogLineN(logIPFilter, CFormat(wxT("IPfiltered source IP=%s received from Kademlia")) % Uint32toStringIP(ED2KID)); return; } if( (ip == Kademlia::CKademlia::GetIPAddress() || ED2KID == theApp->GetED2KID()) && tcp == thePrefs::GetPort()) { AddDebugLogLineN(logKadSearch, wxT("Trying to add myself as source, ignore")); return; } CUpDownClient* ctemp = NULL; switch (type) { case 4: case 1: { // NonFirewalled users if(!tcp) { AddDebugLogLineN(logKadSearch, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, no tcp port received")) % Uint32toStringIP(ip)); return; } if (!IsGoodIP(ED2KID,thePrefs::FilterLanIPs())) { AddDebugLogLineN(logKadSearch, CFormat(wxT("%s got filtered")) % Uint32toStringIP(ED2KID)); AddDebugLogLineN(logIPFilter, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, filtered")) % Uint32toStringIP(ED2KID)); return; } ctemp = new CUpDownClient(tcp, ip, 0, 0, temp, false, true); ctemp->SetSourceFrom(SF_KADEMLIA); // not actually sent or needed for HighID sources //ctemp->SetServerIP(serverip); //ctemp->SetServerPort(serverport); ctemp->SetKadPort(udp); byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); break; } case 2: { // Don't use this type... Some clients will process it wrong.. break; } case 5: case 3: { // This will be a firewalled client connected to Kad only. // We set the clientID to 1 as a Kad user only has 1 buddy. ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true); // The only reason we set the real IP is for when we get a callback // from this firewalled source, the compare method will match them. ctemp->SetSourceFrom(SF_KADEMLIA); ctemp->SetKadPort(udp); byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); pbuddyID->ToByteArray(cID); ctemp->SetBuddyID(cID); ctemp->SetBuddyIP(buddyip); ctemp->SetBuddyPort(buddyport); break; } case 6: { // firewalled source which supports direct UDP callback // if we are firewalled ourself, the source is useless to us if (theApp->IsFirewalled()) { break; } if ((byCryptOptions & 0x08) == 0){ AddDebugLogLineN(logKadSearch, CFormat(wxT("Received Kad source type 6 (direct callback) which has the direct callback flag not set (%s)")) % Uint32toStringIP(ED2KID)); break; } ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true); ctemp->SetSourceFrom(SF_KADEMLIA); ctemp->SetKadPort(udp); ctemp->SetIP(ED2KID); // need to set the IP address, which cannot be used for TCP but for UDP byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); } } if (ctemp) { // add encryption settings ctemp->SetConnectOptions(byCryptOptions); AddDebugLogLineN(logKadSearch, CFormat(wxT("Happily adding a source (%s) type %d")) % Uint32_16toStringIP_Port(ED2KID, ctemp->GetUserPort()) % type); CheckAndAddSource(temp, ctemp); } }
void CServerWnd::UpdateKadInfo() { wxListCtrl* KadInfoList = CastChild( ID_KADINFO, wxListCtrl ); int next_row = 0; KadInfoList->DeleteAllItems(); KadInfoList->InsertItem(next_row, _("Kademlia Status:")); if (theApp->IsKadRunning()) { KadInfoList->SetItem(next_row++, 1, (theApp->IsKadRunningInLanMode() ? _("Running in LAN mode") : _("Running"))); // Connection data KadInfoList->InsertItem(next_row, _("Status:")); KadInfoList->SetItem(next_row++, 1, theApp->IsConnectedKad() ? _("Connected"): _("Disconnected")); if (theApp->IsConnectedKad()) { KadInfoList->InsertItem(next_row, _("Connection State:")); KadInfoList->SetItem(next_row++, 1, theApp->IsFirewalledKad() ? wxString(CFormat(_("Firewalled - open TCP port %d in your router or firewall")) % thePrefs::GetPort()) : wxString(_("OK"))); KadInfoList->InsertItem(next_row, _("UDP Connection State:")); bool UDPFirewalled = theApp->IsFirewalledKadUDP(); KadInfoList->SetItem(next_row++, 1, UDPFirewalled ? wxString(CFormat(_("Firewalled - open UDP port %d in your router or firewall")) % thePrefs::GetUDPPort()) : wxString(_("OK"))); if (theApp->IsFirewalledKad() || UDPFirewalled) { KadInfoList->InsertItem(next_row, _("Firewalled state: ")); wxString BuddyState; switch ( theApp->GetBuddyStatus() ) { case Disconnected: if (!theApp->IsFirewalledKad()) { BuddyState = _("No buddy required - TCP port open"); } else if (!UDPFirewalled) { BuddyState = _("No buddy required - UDP port open"); } else { BuddyState = _("No buddy"); } break; case Connecting: BuddyState = _("Connecting to buddy"); break; case Connected: BuddyState = CFormat(_("Connected to buddy at %s")) % Uint32_16toStringIP_Port(theApp->GetBuddyIP(), theApp->GetBuddyPort()); break; } KadInfoList->SetItem(next_row++, 1, BuddyState); } KadInfoList->InsertItem(next_row, _("IP address:")); KadInfoList->SetItem(next_row++, 1, Uint32toStringIP(theApp->GetKadIPAdress())); // Index info KadInfoList->InsertItem(next_row, _("Indexed sources:")); KadInfoList->SetItem(next_row++, 1, CFormat(wxT("%d")) % theApp->GetKadIndexedSources()); KadInfoList->InsertItem(next_row, _("Indexed keywords:")); KadInfoList->SetItem(next_row++, 1, CFormat(wxT("%d")) % theApp->GetKadIndexedKeywords()); KadInfoList->InsertItem(next_row, _("Indexed notes:")); KadInfoList->SetItem(next_row++, 1, CFormat(wxT("%d")) % theApp->GetKadIndexedNotes()); KadInfoList->InsertItem(next_row, _("Indexed load:")); KadInfoList->SetItem(next_row++, 1, CFormat(wxT("%d")) % theApp->GetKadIndexedLoad()); KadInfoList->InsertItem(next_row, _("Average Users:")); KadInfoList->SetItem(next_row, 1, CastItoIShort(theApp->GetKadUsers())); ++next_row; KadInfoList->InsertItem(next_row, _("Average Files:")); KadInfoList->SetItem(next_row, 1, CastItoIShort(theApp->GetKadFiles())); } } else { // No data KadInfoList->SetItem(next_row, 1, _("Not running")); } // Fit the width of the columns KadInfoList->SetColumnWidth(0, -1); KadInfoList->SetColumnWidth(1, -1); }
void CClientList::Process() { const uint32 cur_tick = ::GetTickCount(); if (m_dwLastBannCleanUp + BAN_CLEANUP_TIME < cur_tick) { m_dwLastBannCleanUp = cur_tick; ClientMap::iterator it = m_bannedList.begin(); while ( it != m_bannedList.end() ) { if ( it->second + CLIENTBANTIME < cur_tick ) { ClientMap::iterator tmp = it++; m_bannedList.erase( tmp ); theStats::RemoveBannedClient(); } else { ++it; } } } if ( m_dwLastTrackedCleanUp + TRACKED_CLEANUP_TIME < cur_tick ) { m_dwLastTrackedCleanUp = cur_tick; std::map<uint32, CDeletedClient*>::iterator it = m_trackedClientsList.begin(); while ( it != m_trackedClientsList.end() ) { std::map<uint32, CDeletedClient*>::iterator cur_src = it++; if ( cur_src->second->m_dwInserted + KEEPTRACK_TIME < cur_tick ) { delete cur_src->second; m_trackedClientsList.erase( cur_src ); } } } //We need to try to connect to the clients in m_KadList //If connected, remove them from the list and send a message back to Kad so we can send a ACK. //If we don't connect, we need to remove the client.. //The sockets timeout should delete this object. // buddy is just a flag that is used to make sure we are still connected or connecting to a buddy. buddyState buddy = Disconnected; CClientRefSet::iterator current_it = m_KadSources.begin(); while (current_it != m_KadSources.end()) { CUpDownClient* cur_client = current_it->GetClient(); ++current_it; // Won't be used anymore till while loop if( !Kademlia::CKademlia::IsRunning() ) { //Clear out this list if we stop running Kad. //Setting the Kad state to KS_NONE causes it to be removed in the switch below. cur_client->SetKadState(KS_NONE); } switch (cur_client->GetKadState()) { case KS_QUEUED_FWCHECK: case KS_QUEUED_FWCHECK_UDP: //Another client asked us to try to connect to them to check their firewalled status. cur_client->TryToConnect(true); break; case KS_CONNECTING_FWCHECK: //Ignore this state as we are just waiting for results. break; case KS_FWCHECK_UDP: case KS_CONNECTING_FWCHECK_UDP: // We want a UDP firewallcheck from this client and are just waiting to get connected to send the request break; case KS_CONNECTED_FWCHECK: //We successfully connected to the client. //We now send a ack to let them know. if (cur_client->GetKadVersion() >= 7) { // The result is now sent per TCP instead of UDP, because this will fail if our intern port is unreachable. // But we want the TCP testresult regardless if UDP is firewalled, the new UDP state and test takes care of the rest wxASSERT(cur_client->IsConnected()); AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_KAD_FWTCPCHECK_ACK to ") + Uint32toStringIP(cur_client->GetIP())); CPacket *packet = new CPacket(OP_KAD_FWTCPCHECK_ACK, 0, OP_EMULEPROT); cur_client->SafeSendPacket(packet); } else { AddDebugLogLineN(logClientKadUDP, wxT("KadFirewalledAckRes to ") + Uint32_16toStringIP_Port(cur_client->GetIP(), cur_client->GetKadPort())); Kademlia::CKademlia::GetUDPListener()->SendNullPacket(KADEMLIA_FIREWALLED_ACK_RES, wxUINT32_SWAP_ALWAYS(cur_client->GetIP()), cur_client->GetKadPort(), 0, NULL); } //We are done with this client. Set Kad status to KS_NONE and it will be removed in the next cycle. cur_client->SetKadState(KS_NONE); break; case KS_INCOMING_BUDDY: //A firewalled client wants us to be his buddy. //If we already have a buddy, we set Kad state to KS_NONE and it's removed in the next cycle. //If not, this client will change to KS_CONNECTED_BUDDY when it connects. if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } break; case KS_QUEUED_BUDDY: //We are firewalled and want to request this client to be a buddy. //But first we check to make sure we are not already trying another client. //If we are not already trying. We try to connect to this client. //If we are already connected to a buddy, we set this client to KS_NONE and it's removed next cycle. //If we are trying to connect to a buddy, we just ignore as the one we are trying may fail and we can then try this one. if( m_nBuddyStatus == Disconnected ) { buddy = Connecting; m_nBuddyStatus = Connecting; cur_client->SetKadState(KS_CONNECTING_BUDDY); cur_client->TryToConnect(true); Notify_ServerUpdateED2KInfo(); } else { if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } } break; case KS_CONNECTING_BUDDY: //We are trying to connect to this client. //Although it should NOT happen, we make sure we are not already connected to a buddy. //If we are we set to KS_NONE and it's removed next cycle. //But if we are not already connected, make sure we set the flag to connecting so we know //things are working correctly. if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } else { wxASSERT( m_nBuddyStatus == Connecting ); buddy = Connecting; } break; case KS_CONNECTED_BUDDY: //A potential connected buddy client wanting to me in the Kad network //We set our flag to connected to make sure things are still working correctly. buddy = Connected; //If m_nBuddyStatus is not connected already, we set this client as our buddy! if( m_nBuddyStatus != Connected ) { m_pBuddy.Link(cur_client CLIENT_DEBUGSTRING("CClientList::Process KS_CONNECTED_BUDDY m_pBuddy.Link")); m_nBuddyStatus = Connected; Notify_ServerUpdateED2KInfo(); } if( m_pBuddy.GetClient() == cur_client && theApp->IsFirewalled() && cur_client->SendBuddyPingPong() ) { cur_client->SendBuddyPing(); } break; default: RemoveFromKadList(cur_client); } } //We either never had a buddy, or lost our buddy.. if( buddy == Disconnected ) { if( m_nBuddyStatus != Disconnected || m_pBuddy.IsLinked() ) { if( Kademlia::CKademlia::IsRunning() && theApp->IsFirewalled() && Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) ) { //We are a lowID client and we just lost our buddy. //Go ahead and instantly try to find a new buddy. Kademlia::CKademlia::GetPrefs()->SetFindBuddy(); } m_pBuddy.Unlink(); m_nBuddyStatus = Disconnected; Notify_ServerUpdateED2KInfo(); } } if ( Kademlia::CKademlia::IsConnected() ) { // we only need a buddy if direct callback is not available if(Kademlia::CKademlia::IsFirewalled() && Kademlia::CUDPFirewallTester::IsFirewalledUDP(true)) { // TODO: Kad buddies won't work with RequireCrypt, so it is disabled for now, but should (and will) // be fixed in later version // Update: buddy connections themselves support obfuscation properly since eMule 0.49a and aMule SVN 2008-05-09 // (this makes it work fine if our buddy uses require crypt), however callback requests don't support it yet so we // wouldn't be able to answer callback requests with RequireCrypt, protocolchange intended for eMule 0.49b if(m_nBuddyStatus == Disconnected && Kademlia::CKademlia::GetPrefs()->GetFindBuddy() && !thePrefs::IsClientCryptLayerRequired()) { AddDebugLogLineN(logKadMain, wxT("Starting BuddySearch")); //We are a firewalled client with no buddy. We have also waited a set time //to try to avoid a false firewalled status.. So lets look for a buddy.. if (!Kademlia::CSearchManager::PrepareLookup(Kademlia::CSearch::FINDBUDDY, true, Kademlia::CUInt128(true) ^ (Kademlia::CKademlia::GetPrefs()->GetKadID()))) { //This search ID was already going. Most likely reason is that //we found and lost our buddy very quickly and the last search hadn't //had time to be removed yet. Go ahead and set this to happen again //next time around. Kademlia::CKademlia::GetPrefs()->SetFindBuddy(); } } } else { if (m_pBuddy.IsLinked()) { //Lets make sure that if we have a buddy, they are firewalled! //If they are also not firewalled, then someone must have fixed their firewall or stopped saturating their line.. //We just set the state of this buddy to KS_NONE and things will be cleared up with the next cycle. if( !m_pBuddy.HasLowID() ) { m_pBuddy.GetClient()->SetKadState(KS_NONE); } } } } else { if (m_pBuddy.IsLinked()) { //We are not connected anymore. Just set this buddy to KS_NONE and things will be cleared out on next cycle. m_pBuddy.GetClient()->SetKadState(KS_NONE); } } CleanUpClientList(); ProcessDirectCallbackList(); }