Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / PeerIPHelper.cs / 1 / PeerIPHelper.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.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Runtime.InteropServices; // IP address helper class for multi-homing support class PeerIPHelper { public event EventHandler AddressChanged; bool isOpen; readonly IPAddress listenAddress; // To listen on a single IP address. IPAddress[] localAddresses; AddressChangeHelper addressChangeHelper; Socket ipv6Socket; object thisLock; const uint Six2FourPrefix = 0x220; const uint TeredoPrefix = 0x00000120; const uint IsatapIdentifier = 0xfe5e0000; enum AddressType { Unknown, Teredo, Isatap, Six2Four } public PeerIPHelper() { Initialize(); } public PeerIPHelper(IPAddress listenAddress) { if (!(listenAddress != null)) { DiagnosticUtility.DebugAssert("listenAddress expected to be non-null"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.listenAddress = listenAddress; Initialize(); } void Initialize() { this.localAddresses = new IPAddress[0]; this.thisLock = new object(); } // NOTE: This is just for suites -- to skip timeout usage internal int AddressChangeWaitTimeout { set { this.addressChangeHelper.Timeout = value; } } object ThisLock { get { return this.thisLock; } } // Compares if the specified collection matches our local cache. Return true on mismatch. public bool AddressesChanged(ReadOnlyCollectionaddresses) { bool changed = false; lock (ThisLock) { if (addresses.Count != this.localAddresses.Length) { changed = true; } else { // If every specified addresses exist in the cache, addresses haven't changed foreach (IPAddress address in this.localAddresses) { if (!addresses.Contains(address)) { changed = true; break; } } } } return changed; } // Since scope ID of IPAddress is mutable, you want to be able to clone an IP address public static IPAddress CloneAddress(IPAddress source, bool maskScopeId) { IPAddress clone = null; if (maskScopeId || V4Address(source)) clone = new IPAddress(source.GetAddressBytes()); else clone = new IPAddress(source.GetAddressBytes(), source.ScopeId); return clone; } // Since scope ID of IPAddress is mutable, you want to be able to clone IP addresses in an array or collection static ReadOnlyCollection CloneAddresses(IPAddress[] sourceArray) { IPAddress [] cloneArray = new IPAddress[sourceArray.Length]; for (int i = 0; i < sourceArray.Length; i++) { cloneArray[i] = CloneAddress(sourceArray[i], false); } return new ReadOnlyCollection (cloneArray); } public static ReadOnlyCollection CloneAddresses(ReadOnlyCollection sourceCollection, bool maskScopeId) { IPAddress[] cloneArray = new IPAddress[sourceCollection.Count]; for (int i = 0; i < sourceCollection.Count; i++) { cloneArray[i] = CloneAddress(sourceCollection[i], maskScopeId); } return new ReadOnlyCollection (cloneArray); } // When listening on a specific IP address, creates an array containing just that address static IPAddress [] CreateAddressArray(IPAddress address) { IPAddress[] addressArray = new IPAddress[1]; addressArray[0] = CloneAddress(address, false); return addressArray; } public void Close() { if (this.isOpen) { lock (ThisLock) { if (this.isOpen) { this.addressChangeHelper.Unregister(); if (this.ipv6Socket != null) { this.ipv6Socket.Close(); } this.isOpen = false; this.addressChangeHelper = null; } } } } // Retrieve the IP addresses configured on the machine. IPAddress [] GetAddresses() { List addresses = new List (); List temporaryAddresses = new List (); if (this.listenAddress != null) // single local address scenario? { // Check if the specified address is configured if (ValidAddress(this.listenAddress)) { return (CreateAddressArray(this.listenAddress)); } } // Walk the interfaces NetworkInterface[] networkIfs = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface networkIf in networkIfs) { if (!ValidInterface(networkIf)) { continue; } // Process each unicast address for the interface. Pick at most one IPv4 and one IPv6 address. // Add remaining eligible addresses on the list to surplus list. We can add these back to the list // being returned, if there is room. IPInterfaceProperties properties = networkIf.GetIPProperties(); if (properties != null) { foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses) { if (NonTransientAddress(unicastAddress)) { if(unicastAddress.SuffixOrigin == SuffixOrigin.Random) temporaryAddresses.Add(unicastAddress.Address); else addresses.Add(unicastAddress.Address); } } } } if(addresses.Count > 0) return ReorderAddresses(addresses); else return temporaryAddresses.ToArray(); } internal static IPAddress[] ReorderAddresses(IEnumerable sourceAddresses) { List result = new List (); List notAdded = new List (); AddressType addressType = AddressType.Unknown; IPAddress v4Address = null, v6Address = null, isatapAddress = null, teredoAddress = null, six2FourAddress = null; foreach (IPAddress address in sourceAddresses) { if (address.AddressFamily == AddressFamily.InterNetwork) { if (v4Address != null) notAdded.Add(address); else { v4Address = address; } continue; } if(address.AddressFamily != AddressFamily.InterNetworkV6 ) { notAdded.Add(address); continue; } if (address.IsIPv6LinkLocal || address.IsIPv6SiteLocal) { notAdded.Add(address); continue; } addressType = GetAddressType(address); switch (addressType) { case AddressType.Teredo: { if (teredoAddress == null) { teredoAddress = address; } else { notAdded.Add(address); } continue; } case AddressType.Six2Four: { if (six2FourAddress == null) { six2FourAddress = address; } else { notAdded.Add(address); } continue; } case AddressType.Isatap: { if (isatapAddress == null) { isatapAddress = address; } else { notAdded.Add(address); } continue; } default: { if (v6Address != null) notAdded.Add(address); else { v6Address = address; } continue; } } } if (six2FourAddress != null) result.Add(six2FourAddress); if (teredoAddress != null) result.Add(teredoAddress); if (isatapAddress != null) result.Add(isatapAddress); if (v6Address != null) result.Add(v6Address); if (v4Address != null) result.Add(v4Address); result.AddRange(notAdded); return result.ToArray(); } static AddressType GetAddressType(IPAddress address) { AddressType result = AddressType.Unknown; byte[] bytes = address.GetAddressBytes(); if (BitConverter.ToUInt16(bytes, 0) == Six2FourPrefix) result = AddressType.Six2Four; else if(BitConverter.ToUInt32(bytes, 0) == TeredoPrefix) result = AddressType.Teredo; else if(BitConverter.ToUInt32(bytes, 8) == IsatapIdentifier) result = AddressType.Isatap; return result; } // Given an EPR, replaces its URI with the specified IP address public static EndpointAddress GetIPEndpointAddress(EndpointAddress epr, IPAddress address) { EndpointAddressBuilder eprBuilder = new EndpointAddressBuilder(epr); eprBuilder.Uri = GetIPUri(epr.Uri, address); return eprBuilder.ToEndpointAddress(); } // Given a hostName based URI, replaces hostName with the IP address public static Uri GetIPUri(Uri uri, IPAddress ipAddress) { UriBuilder uriBuilder = new UriBuilder(uri); if (V6Address(ipAddress) && (ipAddress.IsIPv6LinkLocal || ipAddress.IsIPv6SiteLocal)) { // We make a copy of the IP address because scopeID will not be part of ToString() if set after IP address was created uriBuilder.Host = new IPAddress(ipAddress.GetAddressBytes(), ipAddress.ScopeId).ToString(); } else { uriBuilder.Host = ipAddress.ToString(); } return uriBuilder.Uri; } // Retrieve the currently configured addresses (cached) public ReadOnlyCollection GetLocalAddresses() { lock (ThisLock) { // Return a clone of the address cache return CloneAddresses(this.localAddresses); } } // An address is valid if it is a non-transient addresss (if global, must be DNS-eligible as well) static bool NonTransientAddress(UnicastIPAddressInformation address) { return (!address.IsTransient); } public static bool V4Address(IPAddress address) { return address.AddressFamily == AddressFamily.InterNetwork; } public static bool V6Address(IPAddress address) { return address.AddressFamily == AddressFamily.InterNetworkV6; } // Returns true if the specified address is configured on the machine public static bool ValidAddress (IPAddress address) { // Walk the interfaces NetworkInterface[] networkIfs = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface networkIf in networkIfs) { if (ValidInterface(networkIf)) { IPInterfaceProperties properties = networkIf.GetIPProperties(); if (properties != null) { foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses) { if (address.Equals(unicastAddress.Address)) { return true; } } } } } return false; } static bool ValidInterface (NetworkInterface networkIf) { return (networkIf.NetworkInterfaceType != NetworkInterfaceType.Loopback && networkIf.OperationalStatus == OperationalStatus.Up); } // Process the address change notification from the system and check if the addresses // have really changed. If so, update the local cache and notify interested parties. void OnAddressChanged() { bool changed = false; IPAddress[] newAddresses = GetAddresses(); lock (ThisLock) { if (AddressesChanged(Array.AsReadOnly (newAddresses))) { this.localAddresses = newAddresses; changed = true; } } if (changed) { EventHandler handler = AddressChanged; if (handler != null && this.isOpen) { handler(this, EventArgs.Empty); } } } public void Open() { lock (ThisLock) { DiagnosticUtility.DebugAssert(!this.isOpen, "Helper not expected to be open"); // Register for addr changed event and retrieve addresses from the system this.addressChangeHelper = new AddressChangeHelper(OnAddressChanged); this.localAddresses = GetAddresses(); if (Socket.OSSupportsIPv6) { this.ipv6Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.IP); } this.isOpen = true; } } // Sorts the collection of addresses using sort ioctl public ReadOnlyCollection SortAddresses(ReadOnlyCollection addresses) { ReadOnlyCollection sortedAddresses = SocketAddressList.SortAddresses(this.ipv6Socket, listenAddress, addresses); // If listening on specific address, copy the scope ID that we're listing on for the // link and site local addresses in the sorted list (so that the connect will work) if (this.listenAddress != null) { if (this.listenAddress.IsIPv6LinkLocal) { foreach (IPAddress address in sortedAddresses) { if (address.IsIPv6LinkLocal) { address.ScopeId = this.listenAddress.ScopeId; } } } else if (this.listenAddress.IsIPv6SiteLocal) { foreach (IPAddress address in sortedAddresses) { if (address.IsIPv6SiteLocal) { address.ScopeId = this.listenAddress.ScopeId; } } } } return sortedAddresses; } // // Helper class to handle system address change events. Because multiple events can be fired as a result of // a single significant change (such as interface being enabled/disabled), we try to handle the event just // once using the below mechanism: // Start a timer that goes off after Timeout seconds. If get another address change event from the system // within this timespan, reset the timer to go off after another Timeout secs. When the timer finally fires, // the registered handlers are notified. This should minimize (but not completely eliminate -- think wireless // DHCP interface being enabled, for instance -- this could take longer) reacting multiple times for // a single change. // class AddressChangeHelper { public delegate void AddedChangedCallback(); // To avoid processing multiple addr change events within this time span (5 seconds) public int Timeout = 5000; IOThreadTimer timer; AddedChangedCallback addressChanged; public AddressChangeHelper(AddedChangedCallback addressChanged) { DiagnosticUtility.DebugAssert(addressChanged != null, "addressChanged expected to be non-null"); this.addressChanged = addressChanged; this.timer = new IOThreadTimer(new WaitCallback(FireAddressChange), null, true); NetworkChange.NetworkAddressChanged += OnAddressChange; } public void Unregister() { NetworkChange.NetworkAddressChanged -= OnAddressChange; } void OnAddressChange(object sender, EventArgs args) { this.timer.Set(Timeout); } // Now fire address change event to the interested parties void FireAddressChange(object asyncState) { this.timer.Cancel(); this.addressChanged(); } } } } // 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
- PieceDirectory.cs
- PenLineCapValidation.cs
- GeometryGroup.cs
- SqlConnectionPoolGroupProviderInfo.cs
- HtmlEncodedRawTextWriter.cs
- XmlIlVisitor.cs
- ThreadNeutralSemaphore.cs
- Fx.cs
- ProcessHostFactoryHelper.cs
- InternalSafeNativeMethods.cs
- ControlBuilder.cs
- PrimitiveXmlSerializers.cs
- ListCollectionView.cs
- ToolStripItemTextRenderEventArgs.cs
- InstanceDescriptor.cs
- PieceDirectory.cs
- DeferredRunTextReference.cs
- HandlerBase.cs
- BuildResult.cs
- Executor.cs
- securestring.cs
- EmptyTextWriter.cs
- RangeValuePatternIdentifiers.cs
- TriggerBase.cs
- MessageBox.cs
- SafeArchiveContext.cs
- SQLConvert.cs
- BindingMAnagerBase.cs
- TypeUnloadedException.cs
- ILGenerator.cs
- ProcessHostMapPath.cs
- RadioButtonAutomationPeer.cs
- WebRequestModuleElementCollection.cs
- FrameworkElement.cs
- JsonReaderDelegator.cs
- SqlClientWrapperSmiStream.cs
- HostProtectionPermission.cs
- ConnectionProviderAttribute.cs
- XmlDocumentSerializer.cs
- BindingExpressionBase.cs
- DataGridTextBoxColumn.cs
- StringAnimationUsingKeyFrames.cs
- DataRecordInternal.cs
- XmlSchemaSimpleTypeRestriction.cs
- SqlDataSourceConfigureSortForm.cs
- RelOps.cs
- RealProxy.cs
- Condition.cs
- SystemIcons.cs
- CalendarDay.cs
- BasicDesignerLoader.cs
- ListBoxItem.cs
- CookieProtection.cs
- XhtmlBasicObjectListAdapter.cs
- MatrixConverter.cs
- BitmapEffectInput.cs
- ChangeDirector.cs
- MultiPropertyDescriptorGridEntry.cs
- AtomicFile.cs
- RandomDelayQueuedSendsAsyncResult.cs
- IgnoreDeviceFilterElementCollection.cs
- XmlQueryOutput.cs
- EdmProviderManifest.cs
- MetaModel.cs
- SslStreamSecurityUpgradeProvider.cs
- HtmlCalendarAdapter.cs
- WebContext.cs
- NavigationWindowAutomationPeer.cs
- OdbcConnection.cs
- TreeViewHitTestInfo.cs
- ValueSerializerAttribute.cs
- XPathAncestorQuery.cs
- PreDigestedSignedInfo.cs
- PageAdapter.cs
- XmlAttributeAttribute.cs
- OleDbConnectionFactory.cs
- ToolboxComponentsCreatingEventArgs.cs
- InternalConfigHost.cs
- Stack.cs
- WebPartConnectionsCancelVerb.cs
- HttpPostedFile.cs
- DateTimePicker.cs
- configsystem.cs
- TextTreeObjectNode.cs
- FamilyCollection.cs
- InternalException.cs
- XmlElementList.cs
- Main.cs
- Point3D.cs
- FormViewModeEventArgs.cs
- DictationGrammar.cs
- Operand.cs
- WebPartDescriptionCollection.cs
- X509Certificate2Collection.cs
- TransformProviderWrapper.cs
- EntityObject.cs
- DynamicMetaObjectBinder.cs
- XmlLinkedNode.cs
- NetworkCredential.cs
- ReachVisualSerializer.cs