public ClientListImpl() { lastBannCleanUp_ = 0; lastTrackedCleanUp_ = 0; lastClientCleanUp_ = 0; buddyStatus_ = BuddyStateEnum.Disconnected; DeadSourceList = MuleApplication.Instance.CoreObjectManager.CreateDeadSourceList(); DeadSourceList.Init(true); buddy_ = null; }
public void Process() { /////////////////////////////////////////////////////////////////////////// // Cleanup banned client list // uint cur_tick = MpdUtilities.GetTickCount(); if (lastBannCleanUp_ + MuleConstants.BAN_CLEANUP_TIME < cur_tick) { lastBannCleanUp_ = cur_tick; Dictionary <uint, uint> .Enumerator pos = bannedList_.GetEnumerator(); while (pos.MoveNext()) { if (pos.Current.Value + MuleConstants.CLIENTBANTIME < cur_tick) { RemoveBannedClient(pos.Current.Key); } } } /////////////////////////////////////////////////////////////////////////// // Cleanup tracked client list // if (lastTrackedCleanUp_ + MuleConstants.TRACKED_CLEANUP_TIME < cur_tick) { lastTrackedCleanUp_ = cur_tick; Dictionary <uint, DeletedClient> .Enumerator pos = trackedClientsList_.GetEnumerator(); while (pos.MoveNext()) { if (pos.Current.Value.m_dwInserted + MuleConstants.KEEPTRACK_TIME < cur_tick) { trackedClientsList_.Remove(pos.Current.Key); } } } /////////////////////////////////////////////////////////////////////////// // Process Kad client list // //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. BuddyStateEnum buddy = BuddyStateEnum.Disconnected; for (int pos1 = 0; pos1 < kadList_.Count; pos1++) { UpDownClient cur_client = kadList_[pos1]; if (!MuleApplication.Instance.KadEngine.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.KadState = KadStateEnum.KS_NONE; } switch (cur_client.KadState) { case KadStateEnum.KS_QUEUED_FWCHECK: case KadStateEnum.KS_QUEUED_FWCHECK_UDP: //Another client asked us to try to connect to them to check their firewalled status. cur_client.TryToConnect(true, true); break; case KadStateEnum.KS_CONNECTING_FWCHECK: //Ignore this state as we are just waiting for results. break; case KadStateEnum.KS_FWCHECK_UDP: case KadStateEnum.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 KadStateEnum.KS_CONNECTED_FWCHECK: //We successfully connected to the client. //We now send a ack to let them know. if (cur_client.KadVersion >= (byte)VersionsEnum.KADEMLIA_VERSION7_49a) { // the result is now sent per TCP instead of UDP, because this will fail if our intern UDP 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 Packet pPacket = MuleApplication.Instance.NetworkObjectManager.CreatePacket(OperationCodeEnum.OP_KAD_FWTCPCHECK_ACK, 0, MuleConstants.PROTOCOL_EMULEPROT); if (!cur_client.SafeConnectAndSendPacket(pPacket)) { cur_client = null; } } else { MuleApplication.Instance.KadEngine.UDPListener.SendNullPacket(KadOperationCodeEnum.KADEMLIA_FIREWALLED_ACK_RES, (uint)IPAddress.NetworkToHostOrder(cur_client.IP), cur_client.KadPort, null, null); } //We are done with this client. Set Kad status to KS_NONE and it will be removed in the next cycle. if (cur_client != null) { cur_client.KadState = KadStateEnum.KS_NONE; } break; case KadStateEnum.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 (buddyStatus_ == BuddyStateEnum.Connected) { cur_client.KadState = KadStateEnum.KS_NONE; } break; case KadStateEnum.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 (buddyStatus_ == BuddyStateEnum.Disconnected) { buddy = BuddyStateEnum.Connecting; buddyStatus_ = BuddyStateEnum.Connecting; cur_client.KadState = KadStateEnum.KS_CONNECTING_BUDDY; cur_client.TryToConnect(true, true); } else if (buddyStatus_ == BuddyStateEnum.Connected) { cur_client.KadState = KadStateEnum.KS_NONE; } break; case KadStateEnum.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 (buddyStatus_ == BuddyStateEnum.Connected) { cur_client.KadState = KadStateEnum.KS_NONE; } else { buddy = BuddyStateEnum.Connecting; } break; case KadStateEnum.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 = BuddyStateEnum.Connected; //If m_nBuddyStatus is not connected already, we set this client as our buddy! if (buddyStatus_ != BuddyStateEnum.Connected) { buddy_ = cur_client; buddyStatus_ = BuddyStateEnum.Connected; } if (buddy_ == cur_client && MuleApplication.Instance.IsFirewalled && cur_client.SendBuddyPingPong) { Packet buddyPing = MuleApplication.Instance.NetworkObjectManager.CreatePacket(OperationCodeEnum.OP_BUDDYPING, 0, MuleConstants.PROTOCOL_EMULEPROT); MuleApplication.Instance.Statistics.AddUpDataOverheadOther(buddyPing.Size); cur_client.SetLastBuddyPingPongTime(); } break; default: RemoveFromKadList(cur_client); pos1--; break; } } //We either never had a buddy, or lost our buddy.. if (buddy == BuddyStateEnum.Disconnected) { if (buddyStatus_ != BuddyStateEnum.Disconnected || buddy_ != null) { if (MuleApplication.Instance.KadEngine.IsRunning && MuleApplication.Instance.IsFirewalled && MuleApplication.Instance.KadEngine.UDPFirewallTester.IsFirewalledUDP(true)) { //We are a lowID client and we just lost our buddy. //Go ahead and instantly try to find a new buddy. MuleApplication.Instance.KadEngine.Preference.SetFindBuddy(); } buddy_ = null; buddyStatus_ = BuddyStateEnum.Disconnected; } } if (MuleApplication.Instance.KadEngine.IsConnected) { //we only need a buddy if direct callback is not available if (MuleApplication.Instance.KadEngine.IsFirewalled && MuleApplication.Instance.KadEngine.UDPFirewallTester.IsFirewalledUDP(true)) { //TODO 0.49b: 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 itself support obfuscation properly since 0.49a (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 the next version if (buddyStatus_ == BuddyStateEnum.Disconnected && MuleApplication.Instance.KadEngine.Preference.FindBuddy && !MuleApplication.Instance.Preference.IsClientCryptLayerRequired) { //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 (null == MuleApplication.Instance.KadEngine.SearchManager.PrepareLookup(KadSearchTypeEnum.FINDBUDDY, true, MuleApplication.Instance.KadObjectManager.CreateUInt128(true).Xor(MuleApplication.Instance.KadEngine.Preference.KadID))) { //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. MuleApplication.Instance.KadEngine.Preference.SetFindBuddy(); } } } else { if (buddy_ != null) { //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 (!buddy_.HasLowID) { buddy_.KadState = KadStateEnum.KS_NONE; } } } } else { if (buddy_ != null) { //We are not connected anymore. Just set this buddy to KS_NONE and things will be cleared out on next cycle. buddy_.KadState = KadStateEnum.KS_NONE; } } /////////////////////////////////////////////////////////////////////////// // Cleanup client list // CleanUpClientList(); /////////////////////////////////////////////////////////////////////////// // Process Direct Callbacks for Timeouts // ProcessConnectingClientsList(); }