// 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);
 }