void IFlooderForThrottle.OnThrottleReached() { if (DiagnosticUtility.ShouldTraceInformation) { string message = SR.GetString(SR.PeerThrottleWaiting, this.config.MeshId); PeerThrottleTraceRecord record = new PeerThrottleTraceRecord(this.config.MeshId, message); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerFlooderReceiveMessageQuotaExceeded, SR.GetString(SR.TraceCodePeerFlooderReceiveMessageQuotaExceeded), record, this, null); } IPeerNeighbor peer = this.neighborManager.SlowestNeighbor(); if (peer == null) { return; } UtilityExtension extension = peer.Utility; if (peer.IsConnected && extension != null) { if (extension.PendingMessages > PeerTransportConstants.MessageThreshold) { extension.BeginCheckPoint(new UtilityExtension.PruneNeighborCallback(PruneNeighborCallback)); } else { Fx.Assert(false, "Neighbor is marked slow with messages " + extension.PendingMessages); } FireReachedEvent(); } }
// Notify whoever is interested in NeighborClosed, and start the Maintenance algorithms at threshold public virtual void OnNeighborClosed(IPeerNeighbor neighbor) { if (isOpen) { lock (ThisLock) { if (neighbor != null && neighbor.ListenAddress != null) { EndpointAddress key = neighbor.ListenAddress.EndpointAddress; } if (isOpen && !isRunningMaintenance && neighborManager.ConnectedNeighborCount < config.MinNeighbors) { maintainerTimer.Set(0); } } } NeighborClosedHandler handler = NeighborClosed; if (handler != null) { handler(neighbor); } }
public void AddResult(IAsyncResult result, IPeerNeighbor neighbor) { lock (this.ThisLock) { this.results.Add(result, neighbor); } }
public override void ProcessLinkUtility(IPeerNeighbor neighbor, UtilityInfo utilityInfo) { if (!PeerNeighborStateHelper.IsConnected(neighbor.State)) { neighbor.Abort(PeerCloseReason.InvalidNeighbor, PeerCloseInitiator.LocalNode); } else { try { UtilityExtension.ProcessLinkUtility(neighbor, utilityInfo); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } if (PeerFlooderBase <Message, UtilityInfo> .CloseNeighborIfKnownException(base.neighborManager, exception, neighbor) != null) { throw; } DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } } }
private void OnReferralsAdded(IList <Referral> referrals, IPeerNeighbor neighbor) { bool flag = false; foreach (Referral referral in referrals) { if (!this.disposed) { lock (this.ThisLock) { if (!this.disposed) { if (!this.maintainer.IsOpen) { return; } Uri endpointUri = GetEndpointUri(referral.Address); if (((endpointUri != GetEndpointUri(this.maintainer.GetListenAddress())) && !this.nodeAddresses.ContainsKey(endpointUri)) && (!this.pendingConnectedNeighbor.ContainsKey(endpointUri) && (this.maintainer.FindDuplicateNeighbor(referral.Address) == null))) { this.nodeAddresses[endpointUri] = referral.Address; flag = true; } } } } } if (flag && (this.maintainer.ConnectedNeighborCount < this.wantedConnectionCount)) { this.addNeighbor.Set(); } }
private void SendTerminatingMessage(IPeerNeighbor neighbor, string action, PeerCloseReason closeReason) { if ((this.state == State.Opened) && (closeReason != PeerCloseReason.InvalidNeighbor)) { if (neighbor.TrySetState(PeerNeighborState.Disconnecting)) { Message message; Referral[] referrals = this.maintainer.GetReferrals(); if (action == "http://schemas.microsoft.com/net/2006/05/peer/Disconnect") { DisconnectInfo typedMessage = new DisconnectInfo((DisconnectReason)closeReason, referrals); message = this.DisconnectInfoMessageConverter.ToMessage(typedMessage, MessageVersion.Soap12WSAddressing10); } else { RefuseInfo info2 = new RefuseInfo((RefuseReason)closeReason, referrals); message = this.RefuseInfoMessageConverter.ToMessage(info2, MessageVersion.Soap12WSAddressing10); } this.SendMessageToNeighbor(neighbor, message, null); } else if (neighbor.State < PeerNeighborState.Disconnecting) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); } } }
void PruneNeighborCallback(IPeerNeighbor peer) { lock (ThisLock) { if (this.Neighbors.Count <= 1) { return; } if (DiagnosticUtility.ShouldTraceWarning) { string message = SR.GetString(SR.PeerThrottlePruning, this.config.MeshId); PeerThrottleTraceRecord record = new PeerThrottleTraceRecord(this.config.MeshId, message); TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PeerFlooderReceiveMessageQuotaExceeded, SR.GetString(SR.TraceCodePeerFlooderReceiveMessageQuotaExceeded), record, this, null); } } try { peer.Abort(PeerCloseReason.NodeTooSlow, PeerCloseInitiator.LocalNode); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } if (null != CloseNeighborIfKnownException(neighborManager, e, peer)) { throw; } DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); } }
public void AddResult(IAsyncResult result, IPeerNeighbor neighbor) { lock (ThisLock) { this.results.Add(result, neighbor); } }
private void CleanupOnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { if (this.RemoveTimer(neighbor)) { this.neighborManager.CloseNeighbor(neighbor, reason, PeerCloseInitiator.LocalNode, exception); } }
protected virtual IAsyncResult BeginFloodReceivedMessage(IPeerNeighbor sender, MessageBuffer messageBuffer, TimeSpan timeout, AsyncCallback callback, object state, int index, MessageHeader hopHeader) { this.quotaHelper.AcquireNoQueue(); try { return(this.FloodMessageToNeighbors(messageBuffer, timeout, callback, state, index, hopHeader, sender, this.OnMessageSentHandler)); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } if (!(exception is QuotaExceededException) && (!(exception is CommunicationException) || !(exception.InnerException is QuotaExceededException))) { throw; } System.ServiceModel.DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); if (System.ServiceModel.DiagnosticUtility.ShouldTraceError) { PeerFlooderTraceRecord extendedData = new PeerFlooderTraceRecord(this.config.MeshId, sender.ListenAddress, exception); TraceUtility.TraceEvent(TraceEventType.Error, 0x4004f, System.ServiceModel.SR.GetString("TraceCodePeerFlooderReceiveMessageQuotaExceeded"), extendedData, this, null); } return(null); } }
private void PruneNeighborCallback(IPeerNeighbor peer) { lock (this.ThisLock) { if (this.Neighbors.Count <= 1) { return; } if (System.ServiceModel.DiagnosticUtility.ShouldTraceWarning) { string message = System.ServiceModel.SR.GetString("PeerThrottlePruning", new object[] { this.config.MeshId }); PeerThrottleTraceRecord extendedData = new PeerThrottleTraceRecord(this.config.MeshId, message); TraceUtility.TraceEvent(TraceEventType.Warning, 0x4004f, System.ServiceModel.SR.GetString("TraceCodePeerFlooderReceiveMessageQuotaExceeded"), extendedData, this, null); } } try { peer.Abort(PeerCloseReason.NodeTooSlow, PeerCloseInitiator.LocalNode); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } if (PeerFlooderBase <TFloodContract, TLinkContract> .CloseNeighborIfKnownException(this.neighborManager, exception, peer) != null) { throw; } System.ServiceModel.DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } }
public void OnNeighborAuthenticated(IPeerNeighbor neighbor) { if (this.state == State.Created) { throw Fx.AssertAndThrow("Connector not expected to be in Created state"); } if (!PeerNeighborStateHelper.IsAuthenticatedOrClosed(neighbor.State)) { throw Fx.AssertAndThrow(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Authenticated or Closed, actual state: {0}", new object[] { neighbor.State })); } if (!neighbor.TrySetState(PeerNeighborState.Connecting)) { if (neighbor.State < PeerNeighborState.Faulted) { throw Fx.AssertAndThrow(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Faulted or Closed, actual state: {0}", new object[] { neighbor.State })); } } else if (this.AddTimer(neighbor) && neighbor.IsInitiator) { if (this.neighborManager.ConnectedNeighborCount < this.config.MaxNeighbors) { this.SendConnect(neighbor); } else { this.neighborManager.CloseNeighbor(neighbor, PeerCloseReason.NodeBusy, PeerCloseInitiator.LocalNode); } } }
// Process Disconnect message from the neighbor public void Disconnect(IPeerNeighbor neighbor, DisconnectInfo disconnectInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) { return; } PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList <Referral> referrals = null; if (disconnectInfo.HasBody()) { // We should only receive Disconnect message after the neighbor has transitioned // to connected state. if (neighbor.State >= PeerNeighborState.Connected) { if (PeerConnectorHelper.IsDefined(disconnectInfo.Reason)) { closeReason = (PeerCloseReason)disconnectInfo.Reason; referrals = disconnectInfo.Referrals; } } } // Complete processing of disconnect message CompleteTerminateMessageProcessing(neighbor, closeReason, referrals); }
private void SendMessageToNeighbor(IPeerNeighbor neighbor, Message message, PeerMessageHelpers.CleanupCallback cleanupCallback) { bool flag = false; try { neighbor.Send(message); } catch (Exception exception) { if (Fx.IsFatal(exception)) { flag = true; throw; } if ((!(exception is CommunicationException) && !(exception is QuotaExceededException)) && (!(exception is ObjectDisposedException) && !(exception is TimeoutException))) { throw; } DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); if (cleanupCallback != null) { cleanupCallback(neighbor, PeerCloseReason.InternalFailure, exception); } } finally { if (!flag) { message.Close(); } } }
public void OnNeighborClosing(IPeerNeighbor neighbor, PeerCloseReason closeReason) { if (neighbor.IsConnected) { this.SendTerminatingMessage(neighbor, "http://schemas.microsoft.com/net/2006/05/peer/Disconnect", closeReason); } }
private IPeerNeighbor GetNeighbor() { IPeerNeighbor neighbor = this.getNeighborCallback(OperationContext.Current.GetCallbackChannel <IPeerProxy>()); if ((neighbor == null) || (neighbor.State == PeerNeighborState.Closed)) { if (DiagnosticUtility.ShouldTraceWarning) { TraceUtility.TraceEvent(TraceEventType.Warning, 0x40036, System.ServiceModel.SR.GetString("TraceCodePeerNeighborNotFound"), new PeerNodeTraceRecord(this.config.NodeId), OperationContext.Current.IncomingMessage); } return(null); } if (DiagnosticUtility.ShouldTraceVerbose) { PeerNeighborState state = neighbor.State; PeerNodeAddress listenAddress = null; IPAddress connectIPAddress = null; if ((state >= PeerNeighborState.Opened) && (state <= PeerNeighborState.Connected)) { listenAddress = this.config.GetListenAddress(true); connectIPAddress = this.config.ListenIPAddress; } PeerNeighborTraceRecord extendedData = new PeerNeighborTraceRecord(neighbor.NodeId, this.config.NodeId, listenAddress, connectIPAddress, neighbor.GetHashCode(), neighbor.IsInitiator, state.ToString(), null, null, OperationContext.Current.IncomingMessage.Headers.Action); TraceUtility.TraceEvent(TraceEventType.Verbose, 0x4003a, System.ServiceModel.SR.GetString("TraceCodePeerNeighborMessageReceived"), extendedData, this, null); } return(neighbor); }
bool RemoveTimer(IPeerNeighbor neighbor) { IOThreadTimer timer = null; bool removed = false; // Remove the timer from the table and cancel it. Do this if Connector is // still open. Otherwise, Close method will have already cancelled the timers. lock (ThisLock) { if (this.state == State.Opened && this.timerTable.TryGetValue(neighbor, out timer)) { removed = this.timerTable.Remove(neighbor); } } if (timer != null) { timer.Cancel(); if (!removed) { throw Fx.AssertAndThrow("Neighbor key should have beeen removed from the table"); } } return(removed); }
// Process Refuse message from the neighbor public void Refuse(IPeerNeighbor neighbor, RefuseInfo refuseInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) { return; } PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList <Referral> referrals = null; if (refuseInfo.HasBody()) { // Refuse message should only be received when neighbor is the initiator // and is in connecting state --we accept in closed state to account for // timeouts. if (neighbor.IsInitiator && (neighbor.State == PeerNeighborState.Connecting || neighbor.State == PeerNeighborState.Closed)) { // Remove the entry from timer table for this neighbor RemoveTimer(neighbor); if (PeerConnectorHelper.IsDefined(refuseInfo.Reason)) { closeReason = (PeerCloseReason)refuseInfo.Reason; referrals = refuseInfo.Referrals; } } } // Complete processing of refuse message CompleteTerminateMessageProcessing(neighbor, closeReason, referrals); }
public override void ProcessLinkUtility(IPeerNeighbor neighbor, UtilityInfo utilityInfo) { if (!PeerNeighborStateHelper.IsConnected(neighbor.State)) { neighbor.Abort(PeerCloseReason.InvalidNeighbor, PeerCloseInitiator.LocalNode); return; } try { UtilityExtension.ProcessLinkUtility(neighbor, utilityInfo); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } if (null != CloseNeighborIfKnownException(neighborManager, e, neighbor)) { throw; } DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); } }
public void OnNeighborOpened(object sender, EventArgs args) { IPeerNeighbor neighbor = sender as IPeerNeighbor; EventHandler handler = this.OnNeighborAuthenticated; if (handler == null) { neighbor.Abort(PeerCloseReason.LeavingMesh, PeerCloseInitiator.LocalNode); return; } if (this.authenticationMode == PeerAuthenticationMode.Password) { if (!(neighbor.Extensions.Find <PeerChannelAuthenticatorExtension>() == null)) { throw Fx.AssertAndThrow("extension already exists!"); } PeerChannelAuthenticatorExtension extension = new PeerChannelAuthenticatorExtension(this, handler, args, this.MeshId); neighbor.Extensions.Add(extension); if (neighbor.IsInitiator) { extension.InitiateHandShake(); } } else { neighbor.TrySetState(PeerNeighborState.Authenticated); handler(sender, args); } }
public void Connect(IPeerNeighbor neighbor, ConnectInfo connectInfo) { if (this.state == State.Opened) { PeerCloseReason none = PeerCloseReason.None; if ((neighbor.IsInitiator || !connectInfo.HasBody()) || ((neighbor.State != PeerNeighborState.Connecting) && (neighbor.State != PeerNeighborState.Closed))) { none = PeerCloseReason.InvalidNeighbor; } else if (this.RemoveTimer(neighbor)) { if (this.neighborManager.ConnectedNeighborCount >= this.config.MaxNeighbors) { none = PeerCloseReason.NodeBusy; } else if (!PeerValidateHelper.ValidNodeAddress(connectInfo.Address)) { none = PeerCloseReason.InvalidNeighbor; } else { PeerCloseReason reason2; IPeerNeighbor neighbor2; string action = "http://schemas.microsoft.com/net/2006/05/peer/Refuse"; this.ValidateNeighbor(neighbor, connectInfo.NodeId, out neighbor2, out reason2, out action); if (neighbor != neighbor2) { this.SendWelcome(neighbor); try { neighbor.ListenAddress = connectInfo.Address; } catch (ObjectDisposedException exception) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } if (!neighbor.TrySetState(PeerNeighborState.Connected) && (neighbor.State < PeerNeighborState.Disconnecting)) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); } if (neighbor2 != null) { this.SendTerminatingMessage(neighbor2, action, reason2); this.neighborManager.CloseNeighbor(neighbor2, reason2, PeerCloseInitiator.LocalNode); } } else { none = reason2; } } } if (none != PeerCloseReason.None) { this.SendTerminatingMessage(neighbor, "http://schemas.microsoft.com/net/2006/05/peer/Refuse", none); this.neighborManager.CloseNeighbor(neighbor, none, PeerCloseInitiator.LocalNode); } } }
// Process neighbor closing notification. public void OnNeighborClosing(IPeerNeighbor neighbor, PeerCloseReason closeReason) { // Send Disconnect message to a Connected neighbor if (neighbor.IsConnected) { SendTerminatingMessage(neighbor, PeerStrings.DisconnectAction, closeReason); } }
void IPeerServiceContract.Refuse(RefuseInfo refuseInfo) { IPeerNeighbor neighbor = this.GetNeighbor(); if (neighbor != null) { this.connector.Refuse(neighbor, refuseInfo); } }
void IPeerServiceContract.Connect(ConnectInfo connectInfo) { IPeerNeighbor neighbor = this.GetNeighbor(); if (neighbor != null) { this.connector.Connect(neighbor, connectInfo); } }
void IPeerServiceContract.LinkUtility(UtilityInfo utilityInfo) { IPeerNeighbor neighbor = this.GetNeighbor(); if (neighbor != null) { this.flooder.ProcessLinkUtility(neighbor, utilityInfo); } }
void IPeerServiceContract.Disconnect(DisconnectInfo disconnectInfo) { IPeerNeighbor neighbor = this.GetNeighbor(); if (neighbor != null) { this.connector.Disconnect(neighbor, disconnectInfo); } }
void IPeerServiceContract.Welcome(WelcomeInfo welcomeInfo) { IPeerNeighbor neighbor = this.GetNeighbor(); if (neighbor != null) { this.connector.Welcome(neighbor, welcomeInfo); } }
// Maintainer is expected to validate and accept the contents of referrals // and to determine how many referrals it will accept from the array. // Neighbor reference is passed in case the Maintainer decided to reject a referral // based on invalid content and close the neighbor. public bool AddReferrals(IList <Referral> referrals, IPeerNeighbor neighbor) { Fx.Assert(null != config.Resolver, ""); bool valid = true; bool canShareReferrals = false; try { canShareReferrals = config.Resolver.CanShareReferrals; } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(SR.GetString(SR.ResolverException), e); } if (referrals != null && canShareReferrals) { foreach (Referral referral in referrals) { // If any referral is invalid then the connection is bad so don't accept any referals from this neighbor. if (referral == null || referral.NodeId == PeerTransportConstants.InvalidNodeId || !PeerValidateHelper.ValidNodeAddress(referral.Address) || !PeerValidateHelper.ValidReferralNodeAddress(referral.Address)) { valid = false; break; } } if (valid) { lock (ThisLock) { foreach (Referral referral in referrals) { EndpointAddress key = referral.Address.EndpointAddress; if (referralCache.Count <= this.config.MaxReferralCacheSize && !referralCache.ContainsKey(key)) { referralCache.Add(key, referral); } } } // Invoke any handler that is interested in Referrals being added. ReferralsAddedHandler handler = ReferralsAdded; if (handler != null) { ReferralsAdded(referrals, neighbor); } } } return(valid); }
public virtual void OnNeighborConnected(IPeerNeighbor neighbor) { NeighborConnectedHandler neighborConnected = this.NeighborConnected; if (neighborConnected != null) { neighborConnected(neighbor); } }
public virtual void OnNeighborConnected(IPeerNeighbor neighbor) { NeighborConnectedHandler handler = NeighborConnected; if (handler != null) { handler(neighbor); } }
private void KillSlowNeighbor() { IPeerNeighbor neighbor = this.neighborManager.SlowestNeighbor(); if (neighbor != null) { neighbor.Abort(PeerCloseReason.NodeTooSlow, PeerCloseInitiator.LocalNode); } }
private void CompleteTerminateMessageProcessing(IPeerNeighbor neighbor, PeerCloseReason closeReason, IList<Referral> referrals) { if (neighbor.TrySetState(PeerNeighborState.Disconnected)) { this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.RemoteNode); } else if (neighbor.State < PeerNeighborState.Disconnected) { throw Fx.AssertAndThrow("Unexpected neighbor state"); } this.maintainer.AddReferrals(referrals, neighbor); }
private bool AddTimer(IPeerNeighbor neighbor) { bool flag = false; lock (this.ThisLock) { if ((this.state == State.Opened) && (neighbor.State == PeerNeighborState.Connecting)) { IOThreadTimer timer = new IOThreadTimer(new Action<object>(this.OnConnectTimeout), neighbor, true); timer.Set(this.config.ConnectTimeout); this.timerTable.Add(neighbor, timer); flag = true; } } return flag; }
public bool PingNeighbor(IPeerNeighbor peer) { bool result = true; Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, PeerStrings.PingAction); try { peer.Ping(message); } catch (Exception e) { if (Fx.IsFatal(e)) throw; DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); peer.Abort(PeerCloseReason.InternalFailure, PeerCloseInitiator.LocalNode); result = false; } return result; }
public void CloseNeighbor(IPeerNeighbor neighbor, PeerCloseReason closeReason, PeerCloseInitiator closeInitiator, Exception closeException) { PeerNeighbor nbr = (PeerNeighbor)neighbor; lock (ThisLock) { if (!(this.state != State.Created)) { throw Fx.AssertAndThrow("Neighbor Manager is not expected to be in Created state"); } // Check that the neighbor is known to neighbor manager if (!this.neighborList.Contains(nbr)) return; } // initiate closing of the neighbor if (closeReason != PeerCloseReason.InvalidNeighbor) { if (!nbr.IsClosing) InvokeAsyncNeighborClose(nbr, closeReason, closeInitiator, closeException, null); } else // Call abort even if neighbor is already closing { nbr.Abort(closeReason, closeInitiator); } }
private void ValidateNeighbor(IPeerNeighbor neighbor, ulong neighborNodeId, out IPeerNeighbor neighborToClose, out PeerCloseReason closeReason, out string action) { neighborToClose = null; closeReason = PeerCloseReason.None; action = null; if (neighborNodeId == 0L) { neighborToClose = neighbor; closeReason = PeerCloseReason.InvalidNeighbor; } else if (neighborNodeId == this.config.NodeId) { neighborToClose = neighbor; closeReason = PeerCloseReason.DuplicateNodeId; } else { try { neighbor.NodeId = neighborNodeId; } catch (ObjectDisposedException exception) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); return; } IPeerNeighbor peer = this.neighborManager.FindDuplicateNeighbor(neighborNodeId, neighbor); if ((peer != null) && this.neighborManager.PingNeighbor(peer)) { closeReason = PeerCloseReason.DuplicateNeighbor; if (neighbor.IsInitiator == peer.IsInitiator) { neighborToClose = neighbor; } else if (this.config.NodeId > neighborNodeId) { neighborToClose = neighbor.IsInitiator ? neighbor : peer; } else { neighborToClose = neighbor.IsInitiator ? peer : neighbor; } } } if ((neighborToClose != null) && (neighborToClose != neighbor)) { if (neighborToClose.State == PeerNeighborState.Connected) { action = "http://schemas.microsoft.com/net/2006/05/peer/Disconnect"; } else if (!neighborToClose.IsInitiator && (neighborToClose.State == PeerNeighborState.Connecting)) { action = "http://schemas.microsoft.com/net/2006/05/peer/Refuse"; } } }
// Validates the new neighbor based on its node ID. If it detects duplicate neighbor condition, // it will return reference to the neighbor that should be closed. void ValidateNeighbor(IPeerNeighbor neighbor, ulong neighborNodeId, out IPeerNeighbor neighborToClose, out PeerCloseReason closeReason, out string action) { neighborToClose = null; closeReason = PeerCloseReason.None; action = null; // Invalid neighbor node Id? if (neighborNodeId == PeerTransportConstants.InvalidNodeId) { neighborToClose = neighbor; closeReason = PeerCloseReason.InvalidNeighbor; } // Neighbor's node ID matches local node Id? else if (neighborNodeId == this.config.NodeId) { neighborToClose = neighbor; closeReason = PeerCloseReason.DuplicateNodeId; } else { // Check for duplicate neighbors (i.e., if another neighbor has the // same node Id as the new neighbor). // Set neighbor's node Id prior to calling FindDuplicateNeighbor. try { neighbor.NodeId = neighborNodeId; } catch (ObjectDisposedException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); return; } IPeerNeighbor duplicateNeighbor = this.neighborManager.FindDuplicateNeighbor(neighborNodeId, neighbor); if (duplicateNeighbor != null && this.neighborManager.PingNeighbor(duplicateNeighbor)) { // We have a duplicate neighbor. Determine which one should be closed closeReason = PeerCloseReason.DuplicateNeighbor; // In the corner case where both neighbors are initiated by the same node, // close the new neighbor -- Maintainer is expected to check if there is // already a connection to a node prior to initiating a new connection. if (neighbor.IsInitiator == duplicateNeighbor.IsInitiator) neighborToClose = neighbor; // Otherwise, close the neighbor that was initiated by the node with the // larger node ID -- this ensures that both nodes tear down the same link. else if (this.config.NodeId > neighborNodeId) neighborToClose = (neighbor.IsInitiator ? neighbor : duplicateNeighbor); else neighborToClose = (neighbor.IsInitiator ? duplicateNeighbor : neighbor); } } if (neighborToClose != null) { // If we decided to close the other neighbor, go ahead and do it. if (neighborToClose != neighbor) { // Send Disconnect or Refuse message depending on its state if (neighborToClose.State == PeerNeighborState.Connected) { action = PeerStrings.DisconnectAction; } else if (!neighborToClose.IsInitiator && neighborToClose.State == PeerNeighborState.Connecting) { action = PeerStrings.RefuseAction; } } } }
// Send Disconnect or Refuse message void SendTerminatingMessage(IPeerNeighbor neighbor, string action, PeerCloseReason closeReason) { // We do not attempt to send the message if Connector is not open // or if the close reason is InvalidNeighbor. if (this.state != State.Opened || closeReason == PeerCloseReason.InvalidNeighbor) return; // Set the neighbor state to disconnecting. TrySetState can fail if the // neighbor is already being closed. Disconnect/Refuse msg not sent in that case. if (neighbor.TrySetState(PeerNeighborState.Disconnecting)) { // Get referrals from the maintainer Referral[] referrals = maintainer.GetReferrals(); // Build and send the message Message message; if (action == PeerStrings.DisconnectAction) { DisconnectInfo disconnectInfo = new DisconnectInfo((DisconnectReason)closeReason, referrals); message = DisconnectInfoMessageConverter.ToMessage(disconnectInfo, MessageVersion.Soap12WSAddressing10); } else { RefuseInfo refuseInfo = new RefuseInfo((RefuseReason)closeReason, referrals); message = RefuseInfoMessageConverter.ToMessage(refuseInfo, MessageVersion.Soap12WSAddressing10); } SendMessageToNeighbor(neighbor, message, null); } else if (!(neighbor.State >= PeerNeighborState.Disconnecting)) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); } }
bool RemoveTimer(IPeerNeighbor neighbor) { IOThreadTimer timer = null; bool removed = false; // Remove the timer from the table and cancel it. Do this if Connector is // still open. Otherwise, Close method will have already cancelled the timers. lock (ThisLock) { if (this.state == State.Opened && this.timerTable.TryGetValue(neighbor, out timer)) { removed = this.timerTable.Remove(neighbor); } } if (timer != null) { timer.Cancel(); if (!removed) { throw Fx.AssertAndThrow("Neighbor key should have beeen removed from the table"); } } return removed; }
// If neighbor cannot transition to connected state, this method cleans up the timer and // closes the neighbor void CleanupOnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { // timer will not be found if neighbor is already closed or connected. if (RemoveTimer(neighbor)) { this.neighborManager.CloseNeighbor(neighbor, reason, PeerCloseInitiator.LocalNode, exception); } }
//this method takes care of closing the message. void SendMessageToNeighbor(IPeerNeighbor neighbor, Message message, PeerMessageHelpers.CleanupCallback cleanupCallback) { bool fatal = false; try { neighbor.Send(message); } catch (Exception e) { if (Fx.IsFatal(e)) { fatal = true; throw; } if (e is CommunicationException || e is QuotaExceededException || e is ObjectDisposedException || e is TimeoutException) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); // Message failed to transmit due to quota exceeding or channel failure if (cleanupCallback != null) { cleanupCallback(neighbor, PeerCloseReason.InternalFailure, e); } } else { throw; } } finally { if (!fatal) message.Close(); } }
// Add a timer for the specified neighbor to the timer table. The timer is only added // if Connector is open and the neighbor is in Connecting state. bool AddTimer(IPeerNeighbor neighbor) { bool added = false; lock (ThisLock) { if (state == State.Opened && neighbor.State == PeerNeighborState.Connecting) { IOThreadTimer timer = new IOThreadTimer(new Action<object>(OnConnectTimeout), neighbor, true); timer.Set(this.config.ConnectTimeout); this.timerTable.Add(neighbor, timer); added = true; } } return added; }
public void Welcome(IPeerNeighbor neighbor, WelcomeInfo welcomeInfo) { if (this.state == State.Opened) { PeerCloseReason none = PeerCloseReason.None; if ((!neighbor.IsInitiator || !welcomeInfo.HasBody()) || ((neighbor.State != PeerNeighborState.Connecting) && (neighbor.State != PeerNeighborState.Closed))) { none = PeerCloseReason.InvalidNeighbor; } else if (this.RemoveTimer(neighbor)) { PeerCloseReason reason2; IPeerNeighbor neighbor2; string action = "http://schemas.microsoft.com/net/2006/05/peer/Refuse"; this.ValidateNeighbor(neighbor, welcomeInfo.NodeId, out neighbor2, out reason2, out action); if (neighbor != neighbor2) { if (this.maintainer.AddReferrals(welcomeInfo.Referrals, neighbor)) { if (!neighbor.TrySetState(PeerNeighborState.Connected) && (neighbor.State < PeerNeighborState.Faulted)) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Faulted; it is " + neighbor.State.ToString()); } if (neighbor2 != null) { this.SendTerminatingMessage(neighbor2, action, reason2); this.neighborManager.CloseNeighbor(neighbor2, reason2, PeerCloseInitiator.LocalNode); } } else { none = PeerCloseReason.InvalidNeighbor; } } else { none = reason2; } } if (none != PeerCloseReason.None) { this.SendTerminatingMessage(neighbor, "http://schemas.microsoft.com/net/2006/05/peer/Disconnect", none); this.neighborManager.CloseNeighbor(neighbor, none, PeerCloseInitiator.LocalNode); } } }
// Process Welcome message from the neighbor public void Welcome(IPeerNeighbor neighbor, WelcomeInfo welcomeInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.None; // Welcome message should only be received when neighbor is the initiator // and is in connecting state --we accept in closed state to account for // timeouts. if (!neighbor.IsInitiator || !welcomeInfo.HasBody() || (neighbor.State != PeerNeighborState.Connecting && neighbor.State != PeerNeighborState.Closed)) { closeReason = PeerCloseReason.InvalidNeighbor; } // Remove the entry from timer table for this neighbor. If entry is still present, // RemoveTimer returns true. Otherwise, neighbor is already being closed and // welcome message will be ignored. else if (RemoveTimer(neighbor)) { // It is allowed for a node to have more than MaxNeighbours when processing a welcome message // Determine if neighbor should be accepted. PeerCloseReason closeReason2; IPeerNeighbor neighborToClose; string action = PeerStrings.RefuseAction; ValidateNeighbor(neighbor, welcomeInfo.NodeId, out neighborToClose, out closeReason2, out action); if (neighbor != neighborToClose) { // Neighbor should be accepted AddReferrals validates the referrals, // if they are valid then the neighbor is accepted. if (this.maintainer.AddReferrals(welcomeInfo.Referrals, neighbor)) { if (!neighbor.TrySetState(PeerNeighborState.Connected)) { if (!(neighbor.State >= PeerNeighborState.Faulted)) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Faulted; it is " + neighbor.State.ToString()); } } if (neighborToClose != null) { // The other neighbor should be closed SendTerminatingMessage(neighborToClose, action, closeReason2); this.neighborManager.CloseNeighbor(neighborToClose, closeReason2, PeerCloseInitiator.LocalNode); } } else { // Referrals were invalid this node is suspicous closeReason = PeerCloseReason.InvalidNeighbor; } } else { closeReason = closeReason2; } } if (closeReason != PeerCloseReason.None) { SendTerminatingMessage(neighbor, PeerStrings.DisconnectAction, closeReason); this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.LocalNode); } }
// Complete processing of Disconnect or Refuse message from the neighbor void CompleteTerminateMessageProcessing(IPeerNeighbor neighbor, PeerCloseReason closeReason, IList<Referral> referrals) { // Close the neighbor after setting the neighbor state to Disconnected. // The set can fail if the neighbor is already being closed and that is ok. if (neighbor.TrySetState(PeerNeighborState.Disconnected)) this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.RemoteNode); else if (!(neighbor.State >= PeerNeighborState.Disconnected)) { throw Fx.AssertAndThrow("Unexpected neighbor state"); } // Hand over the referrals to maintainer this.maintainer.AddReferrals(referrals, neighbor); }
void SendConnect(IPeerNeighbor neighbor) { // We do not attempt to send the message if PeerConnector is not open if (neighbor.State == PeerNeighborState.Connecting && this.state == State.Opened) { // Retrieve the local address. The retrieved address may be null if the node // is shutdown. In that case, don't bother to send connect message since the // node is closing... PeerNodeAddress listenAddress = this.config.GetListenAddress(true); if (listenAddress != null) { ConnectInfo connectInfo = new ConnectInfo(this.config.NodeId, listenAddress); Message message = ConnectInfoMessageConverter.ToMessage(connectInfo, MessageVersion.Soap12WSAddressing10); SendMessageToNeighbor(neighbor, message, OnConnectFailure); } } }
void OnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { CleanupOnConnectFailure(neighbor, reason, exception); }
void SendWelcome(IPeerNeighbor neighbor) { // We do not attempt to send the message if PeerConnector is not open if (state == State.Opened) { // Get referrals from the maintainer Referral[] referrals = maintainer.GetReferrals(); WelcomeInfo welcomeInfo = new WelcomeInfo(this.config.NodeId, referrals); Message message = WelcomeInfoMessageConverter.ToMessage(welcomeInfo, MessageVersion.Soap12WSAddressing10); SendMessageToNeighbor(neighbor, message, OnConnectFailure); } }
// Process neighbor closed notification. public void OnNeighborClosed(IPeerNeighbor neighbor) { // If the neighbor is closed abruptly by the remote node, OnNeighborClosing will // not be invoked. Remove neighbor's timer from the table. RemoveTimer(neighbor); }
// Process neighbor closing notification. public void OnNeighborClosing(IPeerNeighbor neighbor, PeerCloseReason closeReason) { // Send Disconnect message to a Connected neighbor if (neighbor.IsConnected) SendTerminatingMessage(neighbor, PeerStrings.DisconnectAction, closeReason); }
// Process neighbor authenticated notification public void OnNeighborAuthenticated(IPeerNeighbor neighbor) { if (!(this.state != State.Created)) { throw Fx.AssertAndThrow("Connector not expected to be in Created state"); } if (!(PeerNeighborStateHelper.IsAuthenticatedOrClosed(neighbor.State))) { throw Fx.AssertAndThrow(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Authenticated or Closed, actual state: {0}", neighbor.State)); } // setting the state fails if neighbor is already closed or closing // If so, we have nothing to do. if (!neighbor.TrySetState(PeerNeighborState.Connecting)) { if (!(neighbor.State >= PeerNeighborState.Faulted)) { throw Fx.AssertAndThrow(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Faulted or Closed, actual state: {0}", neighbor.State)); } return; } // Add a timer to timer table to transition the neighbor to connected state // within finite duration. The neighbor is closed if the timer fires and the // neighbor has not reached connected state. // The timer is not added if neighbor or connector are closed if (AddTimer(neighbor)) { // Need to send connect message if the neighbor is the initiator if (neighbor.IsInitiator) { if (this.neighborManager.ConnectedNeighborCount < this.config.MaxNeighbors) SendConnect(neighbor); else { // We have max connected neighbors already. So close this one. this.neighborManager.CloseNeighbor(neighbor, PeerCloseReason.NodeBusy, PeerCloseInitiator.LocalNode); } } } }
private void SendWelcome(IPeerNeighbor neighbor) { if (this.state == State.Opened) { Referral[] referrals = this.maintainer.GetReferrals(); WelcomeInfo typedMessage = new WelcomeInfo(this.config.NodeId, referrals); Message message = this.WelcomeInfoMessageConverter.ToMessage(typedMessage, MessageVersion.Soap12WSAddressing10); this.SendMessageToNeighbor(neighbor, message, new PeerMessageHelpers.CleanupCallback(this.OnConnectFailure)); } }
//<Implementation of PeerConnector.IPeerConnectorContract> // Process Connect from the neighbor public void Connect(IPeerNeighbor neighbor, ConnectInfo connectInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.None; // A connect message should only be received by a responder neighbor that is // in Connecting state. If not, we close the neighbor without bothering // to send a Refuse message // A malicious neighbor can format a message with a null connectInfo as an argument if (neighbor.IsInitiator || !connectInfo.HasBody() || (neighbor.State != PeerNeighborState.Connecting && neighbor.State != PeerNeighborState.Closed)) { closeReason = PeerCloseReason.InvalidNeighbor; } // Remove the timer from the timer table for this neighbor. If the timer is not // present, the neighbor is already being closed and the Connect message should // be ignored. else if (RemoveTimer(neighbor)) { // Determine if Welcome or Refuse should be sent // Refuse if node has maximum allowed connected neighbors? if (this.neighborManager.ConnectedNeighborCount >= this.config.MaxNeighbors) closeReason = PeerCloseReason.NodeBusy; else { // Deserialization failed or connect info is invalid? if (!PeerValidateHelper.ValidNodeAddress(connectInfo.Address)) { closeReason = PeerCloseReason.InvalidNeighbor; } else { // Determine if neighbor should be accepted. PeerCloseReason closeReason2; IPeerNeighbor neighborToClose; string action = PeerStrings.RefuseAction; ValidateNeighbor(neighbor, connectInfo.NodeId, out neighborToClose, out closeReason2, out action); if (neighbor != neighborToClose) // new neighbor should be accepted { SendWelcome(neighbor); try { neighbor.ListenAddress = connectInfo.Address; } catch (ObjectDisposedException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); } if (!neighbor.TrySetState(PeerNeighborState.Connected)) if (!(neighbor.State >= PeerNeighborState.Disconnecting)) { throw Fx.AssertAndThrow("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); } if (neighborToClose != null) { // The other neighbor should be closed SendTerminatingMessage(neighborToClose, action, closeReason2); this.neighborManager.CloseNeighbor(neighborToClose, closeReason2, PeerCloseInitiator.LocalNode); } } else closeReason = closeReason2; } } } if (closeReason != PeerCloseReason.None) { SendTerminatingMessage(neighbor, PeerStrings.RefuseAction, closeReason); this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.LocalNode); } }
// // Close the specified neighbor. Ok to call multiple times, but NeighborClosing // and NeighborClosed events are fired just once. // If the closeReason specified is InvalidNeighbor, it will be closed ungracefully // public void CloseNeighbor(IPeerNeighbor neighbor, PeerCloseReason closeReason, PeerCloseInitiator closeInitiator) { CloseNeighbor(neighbor, closeReason, closeInitiator, null); }
// Process Disconnect message from the neighbor public void Disconnect(IPeerNeighbor neighbor, DisconnectInfo disconnectInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList<Referral> referrals = null; if (disconnectInfo.HasBody()) { // We should only receive Disconnect message after the neighbor has transitioned // to connected state. if (neighbor.State >= PeerNeighborState.Connected) { if (PeerConnectorHelper.IsDefined(disconnectInfo.Reason)) { closeReason = (PeerCloseReason)disconnectInfo.Reason; referrals = disconnectInfo.Referrals; } } } // Complete processing of disconnect message CompleteTerminateMessageProcessing(neighbor, closeReason, referrals); }
// Find a duplicate neighbor (excluding skipNeighbor) matching the nodeID. public IPeerNeighbor FindDuplicateNeighbor(ulong nodeId, IPeerNeighbor skipNeighbor) { PeerNeighbor duplicateNeighbor = null; if (nodeId != PeerTransportConstants.InvalidNodeId) { lock (ThisLock) { foreach (PeerNeighbor neighbor in this.neighborList) { // We restrict search to neighbors that are not yet closing. if (neighbor != (PeerNeighbor)skipNeighbor && neighbor.NodeId == nodeId && !neighbor.IsClosing && neighbor.State < PeerNeighborState.Disconnecting) { duplicateNeighbor = neighbor; break; } } } } return duplicateNeighbor; }
// Process Refuse message from the neighbor public void Refuse(IPeerNeighbor neighbor, RefuseInfo refuseInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList<Referral> referrals = null; if (refuseInfo.HasBody()) { // Refuse message should only be received when neighbor is the initiator // and is in connecting state --we accept in closed state to account for // timeouts. if (neighbor.IsInitiator && (neighbor.State == PeerNeighborState.Connecting || neighbor.State == PeerNeighborState.Closed)) { // Remove the entry from timer table for this neighbor RemoveTimer(neighbor); if (PeerConnectorHelper.IsDefined(refuseInfo.Reason)) { closeReason = (PeerCloseReason)refuseInfo.Reason; referrals = refuseInfo.Referrals; } } } // Complete processing of refuse message CompleteTerminateMessageProcessing(neighbor, closeReason, referrals); }
// Find a duplicate neighbor (excluding skipNeighbor) matching the address. public IPeerNeighbor FindDuplicateNeighbor(PeerNodeAddress address, IPeerNeighbor skipNeighbor) { PeerNeighbor duplicateNeighbor = null; lock (ThisLock) { foreach (PeerNeighbor neighbor in this.neighborList) { // We restrict search to neighbors that are not yet closing. if (neighbor != (PeerNeighbor)skipNeighbor && neighbor.ListenAddress != null && neighbor.ListenAddress.ServicePath == address.ServicePath && !neighbor.IsClosing && neighbor.State < PeerNeighborState.Disconnecting) { duplicateNeighbor = neighbor; break; } } } return duplicateNeighbor; }