// G----ful shutdown void Shutdown(PeerNeighbor[] neighbors, TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); foreach (PeerNeighbor neighbor in neighbors) CloseNeighbor(neighbor, PeerCloseReason.LeavingMesh, PeerCloseInitiator.LocalNode, null); // Wait for all the neighbors to close (the event object is set when the last // neighbor is closed). Specify a timeout for wait event handle in case event.Set // fails for some reason (it doesn't throw exception). Bail out of the loop when // the neighbor count reaches 0. This ensures that Shutdown() doesn't hang. if (neighbors.Length > 0) { if (!TimeoutHelper.WaitOne(this.shutdownEvent, timeoutHelper.RemainingTime())) { Abort(neighbors); // abort neighbors that haven't been closed yet throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } } }
void RegisterForNeighborEvents(PeerNeighbor neighbor) { neighbor.Opened += OnNeighborOpened; neighbor.Connected += OnNeighborConnected; neighbor.Closed += OnNeighborClosed; // We want the neighbor to call Closing handlers directly, so we delegate neighbor.Closing += this.NeighborClosing; // Disconnecting and Disconnected are treated the same way neighbor.Disconnecting += OnNeighborClosing; neighbor.Disconnected += OnNeighborClosing; }
// Remove neighbor from the list and fire relevant events void RemoveNeighbor(PeerNeighbor neighbor) { bool fireClosed = false; bool fireOffline = false; lock (ThisLock) { if (this.neighborList.Contains(neighbor)) { fireClosed = true; // Remove neighbor from our lists and determine if offline should be fired. this.neighborList.Remove(neighbor); this.connectedNeighborList.Remove(neighbor); if (this.isOnline && this.connectedNeighborList.Count == 0) { this.isOnline = false; fireOffline = true; } // If in the process of shutting down neighbor manager, signal completion // upon closing of the last remaining neighbor if (this.neighborList.Count == 0 && this.shutdownEvent != null) { this.shutdownEvent.Set(); } } } // Fire events if (fireClosed) { FireEvent(NeighborClosed, neighbor, neighbor.CloseReason, neighbor.CloseInitiator, neighbor.CloseException); } else { if (DiagnosticUtility.ShouldTraceWarning) { neighbor.TraceEventHelper(TraceEventType.Warning, TraceCode.PeerNeighborNotFound, SR.GetString(SR.TraceCodePeerNeighborNotFound)); } } if (fireOffline) { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerNeighborManagerOffline, SR.GetString(SR.TraceCodePeerNeighborManagerOffline), this.traceRecord, this, null); } FireEvent(Offline, this); } }
// 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; } } }
// Process an inbound channel public bool ProcessIncomingChannel(IClientChannel channel) { bool accepted = false; IPeerProxy proxy = (IPeerProxy)channel; Fx.Assert(GetNeighborFromProxy(proxy) == null, "Channel should not map to an existing neighbor"); if (this.state == State.Opened) { // It is okay if neighbor manager is closed after the above check because the // new neighbor is only added to neighborList in neighbor Opened handler if the // neighbor manager is still open. PeerNeighbor neighbor = new PeerNeighbor(this.config, this.messageHandler); RegisterForNeighborEvents(neighbor); neighbor.Open(proxy); accepted = true; } else { if (DiagnosticUtility.ShouldTraceWarning) { TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PeerNeighborNotAccepted, SR.GetString(SR.TraceCodePeerNeighborNotAccepted), this.traceRecord, this, null); } } return accepted; }
static void FireEvent(EventHandler handler, PeerNeighbor neighbor) { if (handler != null) handler(neighbor, EventArgs.Empty); }
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 PeerNeighborBehavior(PeerNeighbor neighbor) { this.neighbor = neighbor; }
// ClosedCallback is a delegate to determine if caller has closed. If so, we bail out of open operation public NeighborOpenAsyncResult(PeerNeighbor neighbor, PeerNodeAddress remoteAddress, Binding binding, PeerService service, ClosedCallback closedCallback, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.neighbor = neighbor; IAsyncResult result = null; try { result = neighbor.BeginOpen(remoteAddress, binding, service, closedCallback, timeout, Fx.ThunkCallback(new AsyncCallback(OnOpen)), null); if (result.CompletedSynchronously) { neighbor.EndOpen(result); } } catch (Exception e) { if (Fx.IsFatal(e)) throw; neighbor.TraceEventHelper(TraceEventType.Warning, TraceCode.PeerNeighborOpenFailed, SR.GetString(SR.TraceCodePeerNeighborOpenFailed)); throw; } // Indicate [....] completion to the caller if (result.CompletedSynchronously) base.Complete(true); }
internal IAsyncResult BeginOpenNeighborInternal(PeerNodeAddress remoteAddress, TimeSpan timeout, AsyncCallback callback, object asyncState) { PeerNeighbor neighbor = new PeerNeighbor(this.config, this.messageHandler); RegisterForNeighborEvents(neighbor); return new NeighborOpenAsyncResult(neighbor, remoteAddress, this.serviceBinding, this.service, new ClosedCallback(Closed), timeout, callback, asyncState); }
public OpenAsyncResult(PeerNeighbor neighbor, PeerNodeAddress remoteAddress, Binding binding, PeerService service, ClosedCallback closedCallback, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { Fx.Assert(remoteAddress != null && remoteAddress.IPAddresses.Count > 0, "Non-empty IPAddress collection expected"); this.timeoutHelper = new TimeoutHelper(timeout); this.neighbor = neighbor; this.currentIndex = 0; this.completedSynchronously = true; // initially this.remoteAddress = remoteAddress; this.service = service; this.binding = binding; this.onOpen = Fx.ThunkCallback(new AsyncCallback(OnOpen)); this.closed = closedCallback; BeginOpen(); }
// Ungracefully shutdown the neighbor manager void Abort(PeerNeighbor[] neighbors) { foreach (PeerNeighbor neighbor in neighbors) neighbor.Abort(PeerCloseReason.LeavingMesh, PeerCloseInitiator.LocalNode); }