// 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 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()); } } }
private void CleanupOnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { if (this.RemoveTimer(neighbor)) { this.neighborManager.CloseNeighbor(neighbor, reason, PeerCloseInitiator.LocalNode, exception); } }
// 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 PeerNeighborCloseEventArgs(PeerCloseReason reason, PeerCloseInitiator closeInitiator, Exception exception) { this.reason = reason; this.closeInitiator = closeInitiator; this.exception = exception; }
public void OnNeighborClosing(IPeerNeighbor neighbor, PeerCloseReason closeReason) { if (neighbor.IsConnected) { this.SendTerminatingMessage(neighbor, "http://schemas.microsoft.com/net/2006/05/peer/Disconnect", closeReason); } }
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); } }
// 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); } }
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 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); }
public void Disconnect(IPeerNeighbor neighbor, DisconnectInfo disconnectInfo) { if (this.state == State.Opened) { PeerCloseReason invalidNeighbor = PeerCloseReason.InvalidNeighbor; IList <Referral> referrals = null; if ((disconnectInfo.HasBody() && (neighbor.State >= PeerNeighborState.Connected)) && PeerConnectorHelper.IsDefined(disconnectInfo.Reason)) { invalidNeighbor = (PeerCloseReason)disconnectInfo.Reason; referrals = disconnectInfo.Referrals; } this.CompleteTerminateMessageProcessing(neighbor, invalidNeighbor, referrals); } }
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); } } }
// 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); }
public void Refuse(IPeerNeighbor neighbor, RefuseInfo refuseInfo) { if (this.state == State.Opened) { PeerCloseReason invalidNeighbor = PeerCloseReason.InvalidNeighbor; IList <Referral> referrals = null; if ((refuseInfo.HasBody() && neighbor.IsInitiator) && ((neighbor.State == PeerNeighborState.Connecting) || (neighbor.State == PeerNeighborState.Closed))) { this.RemoveTimer(neighbor); if (PeerConnectorHelper.IsDefined(refuseInfo.Reason)) { invalidNeighbor = (PeerCloseReason)refuseInfo.Reason; referrals = refuseInfo.Referrals; } } this.CompleteTerminateMessageProcessing(neighbor, invalidNeighbor, referrals); } }
// 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()); } }
// 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 OnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { CleanupOnConnectFailure(neighbor, reason, exception); }
// 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); }
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()); } } }
// Calls neighbor.BeginClose or EndClose and catches appropriate exceptions for any cleanup. // We use a single method for both BeginClose and EndClose processing since exception handling // is very similar in both cases. void InvokeAsyncNeighborClose(PeerNeighbor neighbor, PeerCloseReason closeReason, PeerCloseInitiator closeInitiator, Exception closeException, IAsyncResult endResult) { // initiate invoking BeginClose or EndClose try { if (endResult == null) { IAsyncResult beginResult = neighbor.BeginClose(closeReason, closeInitiator, closeException, Fx.ThunkCallback(new AsyncCallback(OnNeighborClosedCallback)), neighbor); if (beginResult.CompletedSynchronously) neighbor.EndClose(beginResult); } else { neighbor.EndClose(endResult); } } catch (Exception e) { if (Fx.IsFatal(e)) throw; DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); neighbor.TraceEventHelper(TraceEventType.Warning, TraceCode.PeerNeighborCloseFailed, SR.GetString(SR.TraceCodePeerNeighborCloseFailed), e); // May get InvalidOperationException or ObjectDisposedException due to simultaneous close from both sides (and autoclose is enabled) if (e is InvalidOperationException || e is CommunicationException || e is TimeoutException) { neighbor.Abort(); } else { throw; } } }
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); } }
// Does heavy-lifting of processing closed/faulted events void OnChannelClosedOrFaulted(PeerCloseReason reason) { PeerNeighborState oldState; lock (ThisLock) { // We don't call SetState here because it should not be called inside lock, // and to avoid race conditions, we need to set the state before the lock // can be released. oldState = this.state; this.state = PeerNeighborState.Closed; // Set close reason etc. if they are not already set (as a result of local // node initiating Close) if (!this.isClosing) { this.isClosing = true; this.closeReason = reason; this.closeInitiator = PeerCloseInitiator.RemoteNode; } TraceClosedEvent(oldState); } // Update traces and counters and notify interested parties OnStateChanged(PeerNeighborState.Closed); }
// 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; } } } }
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"; } } }
public PeerNeighborCloseEventArgs(PeerCloseReason reason, PeerCloseInitiator closeInitiator, System.Exception exception) { this.reason = reason; this.closeInitiator = closeInitiator; this.exception = exception; }
// NOTE: Closing handlers not invoked when a neighbor is aborted; but Closed handlers are. public void Abort(PeerCloseReason reason, PeerCloseInitiator closeInit) { lock (ThisLock) { // Set close reason etc. if they are not already set. if (!this.isClosing) { this.isClosing = true; this.closeReason = reason; this.closeInitiator = closeInit; } } Abort(); }
private void OnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { this.CleanupOnConnectFailure(neighbor, reason, exception); }
// 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()); } }
// 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; } } } }
// 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); } }
// // 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); }
//<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); } }
static void FireEvent(EventHandler<PeerNeighborCloseEventArgs> handler, PeerNeighbor neighbor, PeerCloseReason closeReason, PeerCloseInitiator closeInitiator, Exception closeException) { if (handler != null) { PeerNeighborCloseEventArgs args = new PeerNeighborCloseEventArgs( closeReason, closeInitiator, closeException); handler(neighbor, args); } }
public PeerNeighbor(PeerNodeConfig config, IPeerNodeMessageHandling messageHandler) { this.closeReason = PeerCloseReason.None; this.closeInitiator = PeerCloseInitiator.LocalNode; this.config = config; this.state = PeerNeighborState.Created; this.extensions = new ExtensionCollection<IPeerNeighbor>(this, thisLock); this.messageHandler = messageHandler; }
// Close a neighbor gracefully public IAsyncResult BeginClose(PeerCloseReason reason, PeerCloseInitiator closeInit, Exception exception, AsyncCallback callback, object asyncState) { bool callClosing = false; lock (ThisLock) { // Set close reason etc. if they are not already set. if (!this.isClosing) { callClosing = true; this.isClosing = true; this.closeReason = reason; this.closeInitiator = closeInit; this.closeException = exception; } } // Initiate close, if another thread has not already done so.... // NOTE: NeighborClosing handlers should not throw any catchable exceptions. if (callClosing) { EventHandler<PeerNeighborCloseEventArgs> handler = this.Closing; if (handler != null) { try { PeerNeighborCloseEventArgs args = new PeerNeighborCloseEventArgs( reason, closeInitiator, exception); handler(this, args); } catch (Exception e) { if (Fx.IsFatal(e)) throw; Abort(); throw; } } } if (this.channelFactory != null) return this.channelFactory.BeginClose(callback, asyncState); else return this.proxyChannel.BeginClose(callback, asyncState); }
void IPeerMaintainer.CloseNeighbor(IPeerNeighbor neighbor, PeerCloseReason closeReason) { this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.LocalNode); }