Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / PeerMaintainer.cs / 1 / PeerMaintainer.cs
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Collections.Generic;
using System.ServiceModel;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using System.ServiceModel.Diagnostics;
using Microsoft.Win32;
delegate void NeighborClosedHandler(IPeerNeighbor neighbor);
delegate void NeighborConnectedHandler(IPeerNeighbor neighbor);
delegate void MaintainerClosedHandler();
delegate void ReferralsAddedHandler (IList referrals, IPeerNeighbor neighbor);
interface IPeerMaintainer
{
event NeighborClosedHandler NeighborClosed;
event NeighborConnectedHandler NeighborConnected;
event MaintainerClosedHandler MaintainerClosed;
event ReferralsAddedHandler ReferralsAdded;
int ConnectedNeighborCount { get; }
int NonClosingNeighborCount { get; }
bool IsOpen { get; }
IAsyncResult BeginOpenNeighbor(PeerNodeAddress to, TimeSpan timeout, AsyncCallback callback, object asyncState);
IPeerNeighbor EndOpenNeighbor(IAsyncResult result);
void CloseNeighbor(IPeerNeighbor neighbor, PeerCloseReason closeReason);
IPeerNeighbor FindDuplicateNeighbor(PeerNodeAddress address);
PeerNodeAddress GetListenAddress();
IPeerNeighbor GetLeastUsefulNeighbor();
}
interface IConnectAlgorithms : IDisposable
{
void Connect(TimeSpan timeout);
void Initialize(IPeerMaintainer maintainer, PeerNodeConfig config, int wantedConnectedNeighbors, Dictionary referralCache);
void PruneConnections();
void UpdateEndpointsCollection(ICollection src);
}
class PeerMaintainerBase : IPeerMaintainer where TConnectAlgorithms : IConnectAlgorithms, new()
{
public delegate void ConnectCallback(Exception e);
ConnectCallback connectCallback;
PeerNodeConfig config;
PeerFlooder flooder;
PeerNeighborManager neighborManager;
Dictionary referralCache;
object thisLock;
PeerNodeTraceRecord traceRecord;
volatile bool isRunningMaintenance = false; // true indicates performing connection Maintenance
volatile bool isOpen = false;
IOThreadTimer maintainerTimer;
public event ReferralsAddedHandler ReferralsAdded;
object ThisLock
{
get { return thisLock; }
}
public PeerMaintainerBase(PeerNodeConfig config, PeerNeighborManager neighborManager, PeerFlooder flooder)
{
this.neighborManager = neighborManager;
this.flooder = flooder;
this.config = config;
thisLock = new object();
referralCache = new Dictionary();
maintainerTimer = new IOThreadTimer(new WaitCallback(OnMaintainerTimer), this, false);
}
// 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 referrals, IPeerNeighbor neighbor)
{
DiagnosticUtility.DebugAssert(null != config.Resolver, "");
bool valid = true;
bool canShareReferrals = false;
try
{
canShareReferrals = config.Resolver.CanShareReferrals;
}
catch(Exception e)
{
if(DiagnosticUtility.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 void Close()
{
lock(ThisLock)
{
isOpen = false;
}
maintainerTimer.Cancel(); // No reconnect while closed
SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
MaintainerClosedHandler handler = MaintainerClosed;
if (handler != null)
{
handler();
}
}
void InitialConnection(object dummy)
{
// Are we open and is any maintenance activity occuring
if(isOpen)
{
bool continueMaintenance = false;
if(!isRunningMaintenance)
{
lock(ThisLock)
{
if(!isRunningMaintenance)
{
isRunningMaintenance = true;
continueMaintenance = true;
}
}
}
if(continueMaintenance)
{
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerInitialConnect,this.config.MeshId));
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
TimeoutHelper timeoutHelper = new TimeoutHelper(config.MaintainerTimeout);
Exception exception = null;
// The connection algorithm may be pluggable if we provide an api or metadata to enable it.
// I am sure that research would be interested in doing such a thing.
try
{
maintainerTimer.Cancel(); // No reconnect until after connect has succeeded
using(IConnectAlgorithms connectAlgorithm = (IConnectAlgorithms)new TConnectAlgorithms())
{
connectAlgorithm.Initialize(this, config, config.MinNeighbors, referralCache);
if(referralCache.Count == 0)
{
ReadOnlyCollection addresses = ResolveNewAddresses(timeoutHelper.RemainingTime(), false);
connectAlgorithm.UpdateEndpointsCollection(addresses);
}
if(isOpen)
{
connectAlgorithm.Connect(timeoutHelper.RemainingTime());
}
}
}
#pragma warning suppress 56500 // covered by FxCOP
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
exception = e; // Exeption is saved and transferred
}
if(isOpen)
{
try
{
lock(ThisLock)
{
if(isOpen)
{
// No reconnect until after connect has succeeded
if (neighborManager.ConnectedNeighborCount < 1)
{
maintainerTimer.Set(config.MaintainerRetryInterval);
}
else
{
maintainerTimer.Set(config.MaintainerInterval);
}
}
}
}
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
if(exception == null) exception = e; // Exeption is saved and transferred via callback
}
}
lock(ThisLock)
{
isRunningMaintenance = false;
}
if (connectCallback != null)
{
connectCallback(exception);
}
}
}
}
// This activity maintains the connected nodes
void MaintainConnections(object dummy)
{
// Are we open and is any maintenance activity occuring
if(isOpen)
{
bool continueMaintenance = false;
if(!isRunningMaintenance)
{
lock(ThisLock)
{
if(!isRunningMaintenance)
{
isRunningMaintenance = true;
continueMaintenance = true;
}
}
}
if(continueMaintenance)
{
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerStarting, this.config.MeshId));
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
TimeoutHelper timeoutHelper = new TimeoutHelper(config.MaintainerTimeout);
try
{
maintainerTimer.Cancel(); // No reconnect until after connect has succeeded
int currentlyConnected = neighborManager.ConnectedNeighborCount;
if (currentlyConnected != config.IdealNeighbors) // Already at ideal no work to do
{
using(IConnectAlgorithms connectAlgorithm = (IConnectAlgorithms)new TConnectAlgorithms())
{
connectAlgorithm.Initialize(this, config, config.IdealNeighbors, referralCache);
if (currentlyConnected > config.IdealNeighbors)
{
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerPruneMode,this.config.MeshId));
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
connectAlgorithm.PruneConnections();
}
// During Prune some other neighbor may have gone away which leaves us below Ideal
// So try to reconnect
currentlyConnected = neighborManager.ConnectedNeighborCount;
if (currentlyConnected < config.IdealNeighbors)
{
if (referralCache.Count == 0)
{
ReadOnlyCollection addresses = ResolveNewAddresses(timeoutHelper.RemainingTime(), true);
connectAlgorithm.UpdateEndpointsCollection(addresses);
}
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerConnectMode, this.config.MeshId));
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
connectAlgorithm.Connect(timeoutHelper.RemainingTime());
}
}
}
}
#pragma warning suppress 56500 // covered by FxCOP
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
// We ignore all non Fatal exceptions because this is a worker thread, with no user code waiting
}
finally
{
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord("Maintainer cycle finish");
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
}
ResetMaintenance();
}
}
}
void OnMaintainerTimer(object state)
{
IOThreadScheduler.ScheduleCallback(new WaitCallback(MaintainConnections), null);
}
public void RefreshConnection()
{
// Are we open and is any maintenance activity occuring
if(isOpen)
{
bool continueMaintenance = false;
if(!isRunningMaintenance)
{
lock(ThisLock)
{
if(!isRunningMaintenance)
{
isRunningMaintenance = true;
continueMaintenance = true;
}
}
}
if (continueMaintenance)
{
try
{
TimeoutHelper timeoutHelper = new TimeoutHelper(config.MaintainerTimeout);
maintainerTimer.Cancel(); // No maintainer until after connect has succeeded
using(IConnectAlgorithms connectAlgorithm = (IConnectAlgorithms)new TConnectAlgorithms())
{
// Always go to the resolver for RefreshConnection
ReadOnlyCollection addresses = ResolveNewAddresses(timeoutHelper.RemainingTime(), true);
connectAlgorithm.Initialize(this, config, neighborManager.ConnectedNeighborCount + 1, new Dictionary());
if (addresses.Count > 0)
{
if (isOpen)
{
connectAlgorithm.UpdateEndpointsCollection(addresses);
connectAlgorithm.Connect(timeoutHelper.RemainingTime());
}
}
}
}
finally
{
ResetMaintenance();
}
}
}
}
void ResetMaintenance()
{
if(isOpen)
{
lock(ThisLock)
{
if(isOpen)
{
try
{
maintainerTimer.Set(config.MaintainerInterval); // No reconnect until after connect has succeeded
}
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
// We ignore all non Fatal exceptions because this is a worker thread, with no user code waiting
}
}
}
}
lock(ThisLock)
{
isRunningMaintenance = false;
}
}
public void ScheduleConnect(ConnectCallback connectCallback)
{
this.connectCallback = connectCallback;
IOThreadScheduler.ScheduleCallback(new WaitCallback(InitialConnection), null);
}
public Referral[] GetReferrals()
{
DiagnosticUtility.DebugAssert(null != config.Resolver, "");
Referral[] referrals = null;
bool canShareReferrals = false;
try
{
canShareReferrals = config.Resolver.CanShareReferrals;
}
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(SR.GetString(SR.ResolverException), e);
}
if(canShareReferrals)
{
List neighbors = this.neighborManager.GetConnectedNeighbors();
int count = Math.Min(this.config.MaxReferrals, neighbors.Count);
referrals = new Referral[count];
for (int i = 0; i < count; i++)
{
referrals[i] = new Referral(neighbors[i].NodeId, neighbors[i].ListenAddress);
}
}
else
{
referrals = new Referral[0];
}
return referrals;
}
// 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 virtual void OnNeighborConnected(IPeerNeighbor neighbor)
{
NeighborConnectedHandler handler = NeighborConnected;
if (handler != null)
{
handler(neighbor);
}
}
public void Open()
{
traceRecord = new PeerNodeTraceRecord(config.NodeId);
if (isRunningMaintenance)
{
return;
}
lock(ThisLock)
{
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
isOpen = true;
}
}
// Get some addresses and make sure they are not in my neighborlist
ReadOnlyCollection ResolveNewAddresses(TimeSpan timeLeft, bool retryResolve)
{
TimeoutHelper timeoutHelper = new TimeoutHelper(timeLeft);
Dictionary alreadySeen = new Dictionary();
List reply = new List();
// Is this address me
PeerNodeAddress lclNodeAddress = config.GetListenAddress(true);
alreadySeen.Add(lclNodeAddress.ServicePath, lclNodeAddress);
// Maximum of 2 resolves to get new addresses - if the resolver doesn't return us good addresses in 2 goes (8 randomly returned addresses)
// it is probably messing with us
int nresolves = (retryResolve) ? 2 : 1;
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord("Resolving");
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
for (int i = 0; i < nresolves && reply.Count < config.MaxResolveAddresses && isOpen && timeoutHelper.RemainingTime() > TimeSpan.Zero; i++)
{
ReadOnlyCollection addresses;
try
{
addresses = config.Resolver.Resolve(config.MeshId, config.MaxResolveAddresses, timeoutHelper.RemainingTime());
}
catch(Exception e)
{
if(DiagnosticUtility.IsFatal(e)) throw;
if (DiagnosticUtility.ShouldTraceInformation)
{
PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord("Resolve exception "+e.Message);
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity,
record, this, null);
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.ResolverException), e));
}
if (addresses != null)
{
foreach (PeerNodeAddress address in addresses)
{
if (!alreadySeen.ContainsKey(address.ServicePath))
{
alreadySeen.Add(address.ServicePath, address);
if (((IPeerMaintainer)this).FindDuplicateNeighbor(address) == null)
{
reply.Add(address);
}
}
}
}
}
return (new ReadOnlyCollection(reply));
}
// interface IPeerMaintainer implementation
public event NeighborClosedHandler NeighborClosed;
public event NeighborConnectedHandler NeighborConnected;
public event MaintainerClosedHandler MaintainerClosed;
void IPeerMaintainer.CloseNeighbor(IPeerNeighbor neighbor, PeerCloseReason closeReason)
{
neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.LocalNode);
}
IPeerNeighbor IPeerMaintainer.FindDuplicateNeighbor(PeerNodeAddress address)
{
return neighborManager.FindDuplicateNeighbor(address);
}
PeerNodeAddress IPeerMaintainer.GetListenAddress()
{
return config.GetListenAddress(true);
}
IPeerNeighbor IPeerMaintainer.GetLeastUsefulNeighbor()
{
IPeerNeighbor leastUsefulNeighbor = null;
uint minUtility = UInt32.MaxValue;
foreach (IPeerNeighbor neighbor in this.neighborManager.GetConnectedNeighbors())
{
UtilityExtension utilityExtension = neighbor.Extensions.Find();
if (utilityExtension != null && utilityExtension.IsAccurate && utilityExtension.LinkUtility < minUtility && !neighbor.IsClosing)
{
minUtility = utilityExtension.LinkUtility;
leastUsefulNeighbor = neighbor;
}
}
return leastUsefulNeighbor;
}
IAsyncResult IPeerMaintainer.BeginOpenNeighbor(PeerNodeAddress address, TimeSpan timeout, AsyncCallback callback, object asyncState)
{
lock (ThisLock)
{
EndpointAddress key = address.EndpointAddress;
if (referralCache.ContainsKey(key))
{
referralCache.Remove(key);
}
}
return neighborManager.BeginOpenNeighbor(address, timeout, callback, asyncState);
}
IPeerNeighbor IPeerMaintainer.EndOpenNeighbor(IAsyncResult result)
{
return neighborManager.EndOpenNeighbor(result);
}
int IPeerMaintainer.ConnectedNeighborCount
{
get { return neighborManager.ConnectedNeighborCount; }
}
int IPeerMaintainer.NonClosingNeighborCount
{
get { return neighborManager.NonClosingNeighborCount; }
}
bool IPeerMaintainer.IsOpen
{
get { return isOpen; }
}
public void PingConnections()
{
neighborManager.PingNeighbors();
}
public void PingAndRefresh(object state)
{
PingConnections();
if(this.neighborManager.ConnectedNeighborCount < this.config.IdealNeighbors)
MaintainConnections(null);
}
void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if(e.Mode != PowerModes.Resume)
return;
if(!isOpen)
return;
IOThreadScheduler.ScheduleCallback(new WaitCallback(PingAndRefresh), null);
}
}
partial class PeerMaintainer: PeerMaintainerBase
{
public PeerMaintainer(PeerNodeConfig config, PeerNeighborManager neighborManager, PeerFlooder flooder) : base(config, neighborManager, flooder)
{
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Stroke2.cs
- XmlIlGenerator.cs
- GridView.cs
- XmlQueryType.cs
- PeerObject.cs
- ToolStripSeparatorRenderEventArgs.cs
- RequestResizeEvent.cs
- EncodingInfo.cs
- ConfigXmlText.cs
- WebProxyScriptElement.cs
- SoapEnumAttribute.cs
- NoClickablePointException.cs
- ScriptControlDescriptor.cs
- IndexOutOfRangeException.cs
- XmlSchemas.cs
- SQLByteStorage.cs
- DLinqTableProvider.cs
- CanonicalXml.cs
- MulticastDelegate.cs
- COAUTHIDENTITY.cs
- SubpageParagraph.cs
- ImageEditor.cs
- XmlBindingWorker.cs
- FileSecurity.cs
- RSAPKCS1SignatureFormatter.cs
- SqlFunctions.cs
- SqlFlattener.cs
- RoutedUICommand.cs
- QueryGenerator.cs
- BindingMemberInfo.cs
- FilteredAttributeCollection.cs
- HostProtectionPermission.cs
- StateChangeEvent.cs
- LabelDesigner.cs
- LocatorPartList.cs
- Int32RectValueSerializer.cs
- FontTypeConverter.cs
- HttpDebugHandler.cs
- BulletedList.cs
- ImageSourceConverter.cs
- MasterPageParser.cs
- MethodImplAttribute.cs
- WindowsProgressbar.cs
- ProfileEventArgs.cs
- HashHelper.cs
- XmlHelper.cs
- Line.cs
- __FastResourceComparer.cs
- CustomAttributeBuilder.cs
- CodeIdentifiers.cs
- ScopelessEnumAttribute.cs
- ProviderConnectionPointCollection.cs
- XmlWriterSettings.cs
- CustomAttribute.cs
- Membership.cs
- EventLogPermissionEntryCollection.cs
- DataList.cs
- SelectionRangeConverter.cs
- ByeMessageApril2005.cs
- Logging.cs
- SafeNativeMethods.cs
- FrameworkElementFactory.cs
- PipelineModuleStepContainer.cs
- Point.cs
- DataGridViewTopLeftHeaderCell.cs
- TextEditorDragDrop.cs
- ListViewItemSelectionChangedEvent.cs
- FreeFormPanel.cs
- RegistrySecurity.cs
- SessionIDManager.cs
- BoundingRectTracker.cs
- Control.cs
- TypeListConverter.cs
- GenericIdentity.cs
- DataGridItem.cs
- ListViewItem.cs
- Point4D.cs
- InkCanvasSelectionAdorner.cs
- CompositeKey.cs
- MethodRental.cs
- SqlDataSourceTableQuery.cs
- MdbDataFileEditor.cs
- ContentType.cs
- RadioButtonRenderer.cs
- ViewStateAttachedPropertyFeature.cs
- DataGridDetailsPresenterAutomationPeer.cs
- DbConnectionHelper.cs
- SecurityState.cs
- MemberCollection.cs
- ResXDataNode.cs
- CapabilitiesUse.cs
- DataGridLength.cs
- CounterCreationData.cs
- WindowsScrollBarBits.cs
- ProxyElement.cs
- IsolationInterop.cs
- Themes.cs
- OleDbPropertySetGuid.cs
- UnsafeNativeMethods.cs
- ViewCellRelation.cs