Example #1
0
        /// <summary>
        /// Add a contact if possible, based on the algorithm described
        /// in sections 2.2, 2.4 and 4.2
        /// </summary>
        public void AddContact(Contact contact)
        {
            Validate.IsFalse<OurNodeCannotBeAContactException>(ourID == contact.ID, "Cannot add ourselves as a contact!");
            contact.Touch();            // Update the LastSeen to now.

            lock (this)
            {
                KBucket kbucket = GetKBucket(contact.ID);

                if (kbucket.Contains(contact.ID))
                {
                    // Replace the existing contact, updating the network info and LastSeen timestamp.
                    kbucket.UpdateContactInfo(contact);
                }
                else if (kbucket.IsBucketFull)
                {
                    if (CanSplit(kbucket))
                    {
                        // Split the bucket and try again.
                        (KBucket k1, KBucket k2) = kbucket.Split();
                        int idx = GetKBucketIndex(contact.ID);
                        buckets[idx] = k1;
                        buckets.Insert(idx + 1, k2);
                        buckets[idx].Touch();
                        buckets[idx + 1].Touch();
                        AddContact(contact);
                    }
                    else
                    {
                        Contact lastSeenContact = kbucket.Contacts.OrderBy(c => c.LastSeen).First();
                        RpcError error = lastSeenContact.Protocol.Ping(ourContact);

                        if (error.HasError)
                        {
                            // Null continuation is used because unit tests may not initialize a DHT.
                            dht?.DelayEviction(lastSeenContact, contact);
                        }
                        else
                        {
                            // Still can't add the contact, so put it into the pending list.
                            dht?.AddToPending(contact);
                        }
                    }
                }
                else
                {
                    // Bucket isn't full, so just add the contact.
                    kbucket.AddContact(contact);
                    dht?.ContactAddedToBucket(kbucket, contact);
                }
            }
        }