예제 #1
0
 public ClientListImpl()
 {
     lastBannCleanUp_    = 0;
     lastTrackedCleanUp_ = 0;
     lastClientCleanUp_  = 0;
     buddyStatus_        = BuddyStateEnum.Disconnected;
     DeadSourceList      = MuleApplication.Instance.CoreObjectManager.CreateDeadSourceList();
     DeadSourceList.Init(true);
     buddy_ = null;
 }
예제 #2
0
        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();
        }