/// <summary> /// Indicates if a peer needs a maintenance check. /// </summary> /// <param name="peerStatistic">The peer with its statistics.</param> /// <param name="intervalSeconds"></param> /// <returns>True, if the peer needs a maintenance check.</returns> public static bool NeedMaintenance(PeerStatistic peerStatistic, int[] intervalSeconds) { int onlineSec = peerStatistic.OnlineTime / 1000; int index; if (onlineSec <= 0) { index = 0; } else { index = intervalSeconds.Length - 1; for (int i = 0; i < intervalSeconds.Length; i++) { if (intervalSeconds[i] >= onlineSec) { index = i; break; } } } int time = intervalSeconds[index]; long lastTimeWhenChecked = Convenient.CurrentTimeMillis() - peerStatistic.LastSeenOnline; return(lastTimeWhenChecked > TimeSpan.FromSeconds(time).TotalSeconds); }
/// <summary> /// Notifies on update. This method is thread-safe. /// </summary> /// <param name="peerAddress">The address of the updated peer.</param> /// <param name="storedPeerAddress">Contains statistical information.</param> private void NotifyUpdate(PeerAddress peerAddress, PeerStatistic storedPeerAddress) { lock (_peerMapChangeListeners) { foreach (var listener in _peerMapChangeListeners) { listener.PeerUpdated(peerAddress, storedPeerAddress); } } }
/// <summary> /// Adds a neighbor to the neighbor list. If the bag is full, the ID zero or the same /// as our ID, the neighbor is not added. This method is thread-safe. /// </summary> /// <param name="remotePeer">The node to be added.</param> /// <param name="referrer">If we had direct contact and we know for sure that this node /// is online, we set first hand to true. Information from 3rd party peers are always /// second hand and treated as suc.</param> /// <param name="peerConnection"></param> /// <returns>True, if the neighbor could be added or updated. False, otherwise.</returns> public bool PeerFound(PeerAddress remotePeer, PeerAddress referrer, PeerConnection peerConnection) { Logger.Debug("Peer {0} is online. Reporter was {1}.", remotePeer, referrer); bool firstHand = referrer == null; // if we got contacted by this peer, but we did not initiate the connection bool secondHand = remotePeer.Equals(referrer); // if a peer reported about other peers bool thirdHand = !firstHand && !secondHand; // always trust first hand information if (firstHand) { _offlineMap.Remove(remotePeer.PeerId); _shutdownMap.Remove(remotePeer.PeerId); } if (secondHand && !_peerVerification) { _offlineMap.Remove(remotePeer.PeerId); _shutdownMap.Remove(remotePeer.PeerId); } // don't add nodes with zero node ID, don't add myself and don't add nodes marked as bad if (remotePeer.PeerId.IsZero || Self.Equals(remotePeer.PeerId) || Reject(remotePeer)) { return(false); } if (remotePeer.IsFirewalledTcp || remotePeer.IsFirewalledUdp) { return(false); } // if a peer is relayed but cannot provide any relays, it is useless if (remotePeer.IsRelayed && remotePeer.PeerSocketAddresses.Count == 0) { return(false); } bool probablyDead = _offlineMap.ContainsKey(remotePeer.PeerId) || _shutdownMap.ContainsKey(remotePeer.PeerId) || _exceptionMap.ContainsKey(remotePeer.PeerId); if (thirdHand && probablyDead) { Logger.Debug("Don't add {0}.", remotePeer.PeerId); return(false); } int classMember = ClassMember(remotePeer.PeerId); // the peer might have a new port var oldPeerStatistic = UpdateExistingVerifiedPeerAddress(PeerMapVerified[classMember], remotePeer, firstHand); if (oldPeerStatistic != null) { // we update the peer, so we can exit here and report that we have updated it NotifyUpdate(remotePeer, oldPeerStatistic); return(true); } else { if (firstHand || (secondHand && !_peerVerification)) { var map = PeerMapVerified[classMember]; bool inserted = false; lock (map) { // check again, now we are synchronized if (map.ContainsKey(remotePeer.PeerId)) { return(PeerFound(remotePeer, referrer, peerConnection)); } if (map.Count < BagSizeVerified) { var peerStatistic = new PeerStatistic(remotePeer); peerStatistic.SuccessfullyChecked(); map.Add(remotePeer.PeerId, peerStatistic); inserted = true; } } if (inserted) { // if we inserted into the verified map, remove it from the non-verified map var mapOverflow = PeerMapOverflow[classMember]; lock (mapOverflow) { mapOverflow.Remove(remotePeer.PeerId); } NotifyInsert(remotePeer, true); return(true); } } } // if we are here, we did not have this peer, but our verified map was full // check if we have it stored in the non-verified map var mapOverflow2 = PeerMapOverflow[classMember]; lock (mapOverflow2) { PeerStatistic peerStatistic; if (!mapOverflow2.TryGetValue(remotePeer.PeerId, out peerStatistic)) { peerStatistic = new PeerStatistic(remotePeer); } if (firstHand) { peerStatistic.SuccessfullyChecked(); } mapOverflow2.Add(remotePeer.PeerId, peerStatistic); } NotifyInsert(remotePeer, false); return(true); }