Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / PnrpPeerResolver.cs / 1 / PnrpPeerResolver.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Channels { using Microsoft.Win32.SafeHandles; using System.ServiceModel; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Security; using System.ServiceModel.Diagnostics; using System.ServiceModel.PeerResolvers; using System.ServiceProcess; using System.Text; using System.Threading; using System.Xml.Serialization; sealed class PnrpPeerResolver : PeerResolver { UnsafePnrpNativeMethods.PeerNameRegistrar registrar = new UnsafePnrpNativeMethods.PeerNameRegistrar(); static bool isPnrpAvailable; static bool isPnrpInstalled; const UnsafePnrpNativeMethods.PnrpResolveCriteria resolutionScope = UnsafePnrpNativeMethods.PnrpResolveCriteria.NearestNonCurrentProcess; public const int PNRPINFO_HINT = 0x00000001; internal const int CommentLength = 80; internal const byte TcpTransport = 0x01; internal const byte PayloadVersion = 0x01; internal const char PathSeparator = '/'; internal const int MinGuids = 1; internal const int MaxGuids = 2; internal const byte GuidEscape = 0xFF; internal const int MaxAddressEntries = 10; internal const int MaxAddressEntriesV1 = 4; internal const int MaxPathLength = 200; //this is known prefix+any guids static TimeSpan MaxTimeout = new TimeSpan(0, 10, 0); //PNRP validates the timeout to be no greater than 10 minutes static TimeSpan MaxResolveTimeout = new TimeSpan(0, 0, 45); internal const string GlobalCloudName = "Global_"; static object SharedLock = new object(); static Random randomGenerator = new Random(); static TimeSpan TimeToWaitForStatus = TimeSpan.FromSeconds(15); PeerReferralPolicy referralPolicy = PeerReferralPolicy.Share; [Flags] internal enum PnrpResolveScope { None = 0, Global = 1, SiteLocal = 2, LinkLocal = 4, All = Global | SiteLocal | LinkLocal } static PnrpPeerResolver() { // determine if PNRP is installed isPnrpAvailable = false; using (UnsafePnrpNativeMethods.DiscoveryBase db = new UnsafePnrpNativeMethods.DiscoveryBase()) { isPnrpInstalled = db.IsPnrpInstalled(); isPnrpAvailable = db.IsPnrpAvailable(TimeToWaitForStatus); } } internal PnrpPeerResolver():this(PeerReferralPolicy.Share){} internal PnrpPeerResolver(PeerReferralPolicy referralPolicy) { this.referralPolicy = referralPolicy; } static Encoding PnrpEncoder { get { return System.Text.Encoding.UTF8; } } public static bool IsPnrpAvailable { get { return isPnrpAvailable; } } public static bool IsPnrpInstalled { get { return isPnrpInstalled; } } public static IPEndPoint GetHint() { byte[] bytes = new byte[16]; lock(SharedLock) { randomGenerator.NextBytes(bytes); } return new IPEndPoint(new IPAddress(bytes), 0); } // Get the hint for the node in this process that handles this meshid // Get the nodeid for the current node - If the factory is using PrivatePeerNode then this can throw. // in which case use a hint of 0 // The resolver prepends 0. to the meshid so we strip it off before locating the node. // false means that the search must include the current process. public static bool HasPeerNodeForMesh(string meshId) { PeerNodeImplementation node = null; return PeerNodeImplementation.TryGet(meshId, out node); } // PNRP doesn't support registering the same peername by the same identity in the same process. // Thus, we cannot test the PNRP resolver between two nodes in the same process without a little help. // By calling SetMeshExtensions, the resolver will register and resolver different ids, allowing two // nodes to work in the same process. string localExtension; string remoteExtension; internal void SetMeshExtensions(string local, string remote) { localExtension = local; remoteExtension = remote; } internal PnrpResolveScope EnumerateClouds(bool forResolve, DictionaryLinkCloudNames, Dictionary SiteCloudNames) { bool foundActive = false; PnrpResolveScope currentScope = PnrpResolveScope.None; LinkCloudNames.Clear(); SiteCloudNames.Clear(); UnsafePnrpNativeMethods.CloudInfo[] cloudInfos = UnsafePnrpNativeMethods.PeerCloudEnumerator.GetClouds(); // If we are resolving we should first look for active clouds only // If we find some then we should return those to the caller // otherwise we should just load up with clouds if (forResolve) { foreach (UnsafePnrpNativeMethods.CloudInfo cloud in cloudInfos) { if (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Active) { if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.Global) { currentScope |= PnrpResolveScope.Global; foundActive = true; } else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.LinkLocal) { DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress"); LinkCloudNames.Add(cloud.ScopeId, cloud.Name); currentScope |= PnrpResolveScope.LinkLocal; foundActive = true; } else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.SiteLocal) { DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress"); SiteCloudNames.Add(cloud.ScopeId, cloud.Name); currentScope |= PnrpResolveScope.SiteLocal; foundActive = true; } } } } if (!foundActive) { foreach (UnsafePnrpNativeMethods.CloudInfo cloud in cloudInfos) { if (!((cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Dead) || (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Disabled) || (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.NoNet)) ) { if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.Global) { currentScope |= PnrpResolveScope.Global; continue; } if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.LinkLocal) { DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress"); LinkCloudNames.Add(cloud.ScopeId, cloud.Name); currentScope |= PnrpResolveScope.LinkLocal; } else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.SiteLocal) { DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress"); SiteCloudNames.Add(cloud.ScopeId, cloud.Name); currentScope |= PnrpResolveScope.SiteLocal; } } } } return currentScope; } class RegistrationHandle { public string PeerName; public List Clouds; public RegistrationHandle(string peerName) { this.PeerName = peerName; Clouds = new List (); } public void AddCloud(string name) { this.Clouds.Add(name); } } public override bool CanShareReferrals { get { return referralPolicy != PeerReferralPolicy.DoNotShare; } } public override object Register(string meshId, PeerNodeAddress nodeAddress, TimeSpan timeout) { ThrowIfNoPnrp(); PnrpRegistration globalEntry = null; PnrpRegistration[] linkEntries = null; PnrpRegistration[] siteEntries = null; RegistrationHandle regHandle = new RegistrationHandle(meshId); Dictionary SiteCloudNames = new Dictionary (); Dictionary LinkCloudNames = new Dictionary (); PnrpResolveScope availableScope = EnumerateClouds(false, LinkCloudNames, SiteCloudNames); if(availableScope == PnrpResolveScope.None) { //could not find any clouds. PeerExceptionHelper.ThrowInvalidOperation_PnrpNoClouds(); } if (localExtension != null) meshId += localExtension; try { PeerNodeAddressToPnrpRegistrations(meshId, LinkCloudNames, SiteCloudNames, nodeAddress, out linkEntries, out siteEntries, out globalEntry); } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri), e)); } TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); try { PnrpResolveScope currentScope = PnrpResolveScope.None; if(globalEntry != null) { if(globalEntry.Addresses.Length > 0 && (availableScope & PnrpResolveScope.Global) != 0) { registrar.Register(globalEntry, timeoutHelper.RemainingTime()); regHandle.AddCloud(globalEntry.CloudName); currentScope |= PnrpResolveScope.Global; } } if(linkEntries.Length > 0) { foreach(PnrpRegistration entry in linkEntries) { if(entry.Addresses.Length > 0) { registrar.Register(entry, timeoutHelper.RemainingTime()); regHandle.AddCloud(entry.CloudName); } } currentScope |= PnrpResolveScope.LinkLocal; } if(siteEntries.Length > 0) { foreach(PnrpRegistration entry in siteEntries) { if(entry.Addresses.Length > 0) { registrar.Register(entry, timeoutHelper.RemainingTime()); regHandle.AddCloud(entry.CloudName); } } currentScope |= PnrpResolveScope.SiteLocal; } if(currentScope == PnrpResolveScope.None) { // We have addresses but no cloud that corresponds to them // so we should throw an exception PeerExceptionHelper.ThrowInvalidOperation_PnrpAddressesUnsupported(); } } catch(SocketException) { try { Unregister(regHandle,timeoutHelper.RemainingTime()); } catch(SocketException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } throw; } if (DiagnosticUtility.ShouldTraceInformation) { PnrpRegisterTraceRecord record = new PnrpRegisterTraceRecord(meshId,globalEntry,siteEntries,linkEntries); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpRegisteredAddresses, record, this, null); } return regHandle; } void ThrowIfNoPnrp() { if (!isPnrpAvailable) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( SR.GetString(SR.PeerPnrpNotAvailable))); } } public override void Unregister(object registrationId, TimeSpan timeout) { RegistrationHandle regHandle = registrationId as RegistrationHandle; if(regHandle == null || String.IsNullOrEmpty(regHandle.PeerName)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerInvalidRegistrationId, regHandle), "registrationId")); string meshId = regHandle.PeerName; // prepend a 0. for unsecured peername string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshId); registrar.Unregister(peerName, regHandle.Clouds, timeout); if (DiagnosticUtility.ShouldTraceInformation) { PnrpPeerResolverTraceRecord record = new PnrpPeerResolverTraceRecord(meshId, new List ()); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpUnregisteredAddresses, record, this, null); } } public override void Update(object registrationId, PeerNodeAddress updatedNodeAddress, TimeSpan timeout) { RegistrationHandle regHandle = registrationId as RegistrationHandle; if (regHandle == null || string.IsNullOrEmpty(regHandle.PeerName)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerInvalidRegistrationId, regHandle), "registrationId")); string meshId = regHandle.PeerName; Register(meshId, updatedNodeAddress, timeout); } //return null in case of unrecognized format. consider adding logging. PeerNodeAddress PeerNodeAddressFromPnrpRegistration(PnrpRegistration input) { List addresses = new List (); PeerNodeAddress result = null; Guid[] guids ; StringBuilder pathBuilder = new StringBuilder(MaxPathLength); int version=0; string protocolScheme; try { if (input == null || String.IsNullOrEmpty(input.Comment)) return null; Array.ForEach(input.Addresses,delegate(IPEndPoint obj){ addresses.Add(obj.Address);}); if (addresses.Count != 0) { UriBuilder uriBuilder = new UriBuilder(); uriBuilder.Port = input.Addresses[0].Port; uriBuilder.Host = addresses[0].ToString(); pathBuilder.Append(PeerStrings.KnownServiceUriPrefix); CharEncoder.Decode(input.Comment, out version, out protocolScheme, out guids); if ( (version == PayloadVersion) && (guids != null) && (guids.Length <= MaxGuids) && (guids.Length >= MinGuids) ) { uriBuilder.Scheme = protocolScheme; Array.ForEach(guids,delegate(Guid guid) { pathBuilder.Append(PathSeparator + String.Format(CultureInfo.InvariantCulture,"{0}",guid.ToString())); } ); uriBuilder.Path = String.Format(CultureInfo.InvariantCulture,"{0}", pathBuilder.ToString()); result = new PeerNodeAddress(new EndpointAddress(uriBuilder.Uri), new ReadOnlyCollection (addresses)); } } } catch (ArgumentException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } catch (FormatException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } catch (IndexOutOfRangeException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } return result; } void TrimToMaxAddresses(List addressList) { if(addressList.Count > MaxAddressEntries) { addressList.RemoveRange(MaxAddressEntries, addressList.Count-MaxAddressEntries); } } void PeerNodeAddressToPnrpRegistrations(string meshName, Dictionary LinkCloudNames, Dictionary SiteCloudNames, PeerNodeAddress input, out PnrpRegistration[] linkRegs, out PnrpRegistration[] siteRegs, out PnrpRegistration global) { PnrpRegistration reg = new PnrpRegistration(); Dictionary resultsLink = new Dictionary (); Dictionary resultsSite = new Dictionary (); PnrpRegistration entry = null; string scheme; Guid[] guids; ParseServiceUri(input.EndpointAddress.Uri, out scheme, out guids); int port = input.EndpointAddress.Uri.Port; if (port <= 0) port = TcpUri.DefaultPort; string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshName); string comment = CharEncoder.Encode(PayloadVersion, scheme, guids); global = null; string cloudName = string.Empty; foreach(IPAddress address in input.IPAddresses) { if(address.AddressFamily == AddressFamily.InterNetworkV6 && ((address.IsIPv6LinkLocal) || (address.IsIPv6SiteLocal)) ) { if(address.IsIPv6LinkLocal) { if(!resultsLink.TryGetValue((uint)address.ScopeId, out entry)) { if(!LinkCloudNames.TryGetValue((uint)address.ScopeId, out cloudName)) { continue; } entry = PnrpRegistration.Create(peerName,comment,cloudName); resultsLink.Add((uint)address.ScopeId, entry); } } else { if (!resultsSite.TryGetValue((uint)address.ScopeId, out entry)) { if(!SiteCloudNames.TryGetValue((uint)address.ScopeId, out cloudName)) { continue; } entry = PnrpRegistration.Create(peerName,comment,cloudName); resultsSite.Add((uint)address.ScopeId, entry); } } entry.addressList.Add(new IPEndPoint(address,port)); } else { if(global == null) { global = PnrpRegistration.Create(peerName,comment,GlobalCloudName); } global.addressList.Add(new IPEndPoint(address,port)); } } if(global != null) { if(global.addressList != null) { TrimToMaxAddresses(global.addressList); global.Addresses = global.addressList.ToArray(); } else global.Addresses = new IPEndPoint[0]; } if(resultsLink.Count != 0) { foreach(PnrpRegistration tempLink in resultsLink.Values) { if(tempLink.addressList != null) { TrimToMaxAddresses(tempLink.addressList); tempLink.Addresses = tempLink.addressList.ToArray(); } else { tempLink.Addresses = new IPEndPoint[0]; } } linkRegs = new PnrpRegistration[resultsLink.Count]; resultsLink.Values.CopyTo(linkRegs,0); } else linkRegs = new PnrpRegistration[0]; if(resultsSite.Count != 0) { foreach(PnrpRegistration tempSite in resultsSite.Values) { if(tempSite.addressList != null) { TrimToMaxAddresses(tempSite.addressList); tempSite.Addresses = tempSite.addressList.ToArray(); } else { tempSite.Addresses = new IPEndPoint[0]; } } siteRegs = new PnrpRegistration[resultsSite.Count]; resultsSite.Values.CopyTo(siteRegs,0); } else siteRegs = new PnrpRegistration[0]; } static int ProtocolFromName(string name) { if (name == Uri.UriSchemeNetTcp) { return TcpTransport; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("name", SR.GetString(SR.PeerPnrpIllegalUri)); } static string NameFromProtocol(byte number) { switch(number) { case TcpTransport: return Uri.UriSchemeNetTcp; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri))); } } void ParseServiceUri(Uri uri, out string scheme, out Guid[] result) { if(uri != null) { if((ProtocolFromName(uri.Scheme)!=0) && !String.IsNullOrEmpty(uri.AbsolutePath)) { scheme = uri.Scheme; string[] parts = uri.AbsolutePath.Trim(new char[] { ' ',PathSeparator }).Split(PathSeparator); if((0 == String.Compare(parts[0],PeerStrings.KnownServiceUriPrefix,StringComparison.OrdinalIgnoreCase))) { if(parts.Length >= MinGuids && parts.Length <= MaxGuids+1) { result = new Guid[parts.Length-1]; try { for(int i=1;i results, List regs) { PnrpRegistration entry = null; foreach(PnrpRegistration reg in regs) { if(!results.TryGetValue(reg.Comment, out entry)) { entry = reg; results.Add(reg.Comment,reg); entry.addressList = new List (); } entry.addressList.AddRange(reg.Addresses); reg.Addresses = null; } } void MergeResults(List nodeAddressList, List globalRegistrations, List linkRegistrations, List siteRegistrations) { Dictionary results = new Dictionary (); MergeResults(results,globalRegistrations); MergeResults(results,siteRegistrations); MergeResults(results,linkRegistrations); PeerNodeAddress result; foreach(PnrpRegistration reg in results.Values) { reg.Addresses = reg.addressList.ToArray(); result = PeerNodeAddressFromPnrpRegistration(reg); if(result != null) nodeAddressList.Add(result); } } public override ReadOnlyCollection Resolve(string meshId, int maxAddresses, TimeSpan timeout) { ThrowIfNoPnrp(); UnsafePnrpNativeMethods.PeerNameResolver resolver; List resolvers =new List (); List globalRegistrations = new List (); List linkRegistrations = new List (); List siteRegistrations = new List (); List handles = new List (); Dictionary SiteCloudNames = new Dictionary (); Dictionary LinkCloudNames = new Dictionary (); UnsafePnrpNativeMethods.PnrpResolveCriteria targetScope = resolutionScope; TimeoutHelper timeoutHelper = new TimeoutHelper(TimeSpan.Compare(timeout, MaxResolveTimeout) <= 0 ? timeout : MaxResolveTimeout); if(!HasPeerNodeForMesh(meshId)) targetScope = UnsafePnrpNativeMethods.PnrpResolveCriteria.Any; PnrpResolveScope currentScope = EnumerateClouds(true, LinkCloudNames, SiteCloudNames); if (remoteExtension != null) meshId += remoteExtension; // prepend a 0. for unsecured peername string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshId); if((currentScope & PnrpResolveScope.Global) != 0) { resolver = new UnsafePnrpNativeMethods.PeerNameResolver( peerName, maxAddresses, targetScope,0, GlobalCloudName, timeoutHelper.RemainingTime(), globalRegistrations); handles.Add(resolver.AsyncWaitHandle); resolvers.Add(resolver); } if((currentScope & PnrpResolveScope.LinkLocal) != 0) { foreach(KeyValuePair linkEntry in LinkCloudNames) { resolver = new UnsafePnrpNativeMethods.PeerNameResolver( peerName, maxAddresses, targetScope, linkEntry.Key, linkEntry.Value, timeoutHelper.RemainingTime(), linkRegistrations); handles.Add(resolver.AsyncWaitHandle); resolvers.Add(resolver); } } if((currentScope & PnrpResolveScope.SiteLocal) != 0) { foreach(KeyValuePair siteEntry in SiteCloudNames) { resolver = new UnsafePnrpNativeMethods.PeerNameResolver( peerName, maxAddresses, targetScope, siteEntry.Key, siteEntry.Value, timeoutHelper.RemainingTime(), siteRegistrations); handles.Add(resolver.AsyncWaitHandle); resolvers.Add(resolver); } } if(handles.Count == 0) { //could not find any clouds. if (DiagnosticUtility.ShouldTraceWarning) { Exception exception = new InvalidOperationException(SR.GetString(SR.PnrpNoClouds)); PnrpResolveExceptionTraceRecord record = new PnrpResolveExceptionTraceRecord(meshId, string.Empty,exception); TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PnrpResolvedAddresses, record, this, null); } return new ReadOnlyCollection (new List ()); } Exception lastException = null; foreach(UnsafePnrpNativeMethods.PeerNameResolver handle in resolvers) { try { handle.End(); } catch(SocketException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); lastException = e; } } List nodeAddressList = new List (); MergeResults(nodeAddressList, globalRegistrations, linkRegistrations, siteRegistrations); if((lastException != null) && (nodeAddressList.Count == 0)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(lastException); if (DiagnosticUtility.ShouldTraceInformation) { PnrpPeerResolverTraceRecord record = new PnrpPeerResolverTraceRecord(meshId, nodeAddressList); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpResolvedAddresses, record, this, null); } return new ReadOnlyCollection (nodeAddressList); } // contains the friendly PNRP information internal class PnrpRegistration { public string PeerName; public string CloudName; public string Comment; public IPEndPoint[] Addresses; public List addressList; internal static PnrpRegistration Create(string peerName, string comment, string cloudName) { PnrpRegistration reg = new PnrpRegistration(); reg.Comment = comment; reg.CloudName = cloudName; reg.PeerName = peerName; reg.addressList = new List (); return reg; } } internal class CharEncoder { static void CheckAtLimit(int current) { if (current + 1 >= CommentLength) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri))); } static void EncodeByte(byte b, ref int offset, byte[] bytes) { if (b == 0 || b == GuidEscape) { CheckAtLimit(offset); bytes[offset++] = GuidEscape; } CheckAtLimit(offset); bytes[offset++] = b; } static internal string Encode(int version, string protocolName, Guid[] guids) { byte[] bytes = new byte[CommentLength]; int i = 0; int protocol = ProtocolFromName(protocolName); EncodeByte(Convert.ToByte(version), ref i, bytes); EncodeByte(Convert.ToByte(protocol), ref i, bytes); EncodeByte(Convert.ToByte(guids.Length), ref i, bytes); foreach (Guid guid in guids) { foreach (byte b in guid.ToByteArray()) { EncodeByte(Convert.ToByte(b), ref i, bytes); } } if (i % 2 != 0 && i < bytes.Length) bytes[i] = GuidEscape; // Now we have a collection of bytes lets turn it into a string int length = i; int clength = (length / 2) + (length % 2); // Pack 2 bytes per char char[] chars = new char[clength]; i = 0; for (int j = 0; j < clength; j++) { chars[j] = Convert.ToChar(bytes[i++] * 0x100 + bytes[i++]); } return new string(chars); } static byte GetByte(int offset, char[] chars) { int p = offset / 2; int lo = offset % 2; return Convert.ToByte(lo == 1 ? chars[p] & GuidEscape: chars[p] / 0x100); } static byte DecodeByte(ref int offset, char[] chars) { byte b = GetByte(offset++, chars); if (b == 0xff) { b = GetByte(offset++, chars); } return b; } static internal void Decode(string buffer, out int version, out string protocolName, out Guid[] guids) { char[] chars = buffer.ToCharArray(); byte protocol; int i = 0; version = DecodeByte(ref i, chars); protocol = DecodeByte(ref i, chars); protocolName = NameFromProtocol(protocol); int length = DecodeByte(ref i, chars); guids = new Guid[length]; for (int g = 0; g < length; g++) { byte[] bytes = new byte[16]; for (int j = 0; j < 16; j++) { bytes[j] = DecodeByte(ref i, chars); } guids[g] = new Guid(bytes); } } } internal enum PnrpErrorCodes { WSA_PNRP_ERROR_BASE = 11500, WSA_PNRP_CLOUD_NOT_FOUND = 11501, WSA_PNRP_CLOUD_DISABLED = 11502, //these error codes are not relevant for now // WSA_PNRP_INVALID_IDENTITY = 11503, // WSA_PNRP_TOO_MUCH_LOAD = 11504, WSA_PNRP_CLOUD_IS_RESOLVE_ONLY = 11505, // WSA_PNRP_CLIENT_INVALID_COMPARTMENT_ID = 11506, WSA_PNRP_FW_PORT_BLOCKED = 11507, WSA_PNRP_DUPLICATE_PEER_NAME = 11508, } internal class PnrpException : SocketException { string message; internal PnrpException(int errorCode, string cloud) : base(errorCode) { LoadMessage(errorCode, cloud); } public override string Message { get { if(!String.IsNullOrEmpty(message)) return message; else return base.Message; } } void LoadMessage(int errorCode, string cloud) { string formatString; switch((PnrpErrorCodes)errorCode) { case PnrpErrorCodes.WSA_PNRP_CLOUD_DISABLED: formatString = SR.PnrpCloudDisabled; break; case PnrpErrorCodes.WSA_PNRP_CLOUD_NOT_FOUND: formatString = SR.PnrpCloudNotFound; break; case PnrpErrorCodes.WSA_PNRP_CLOUD_IS_RESOLVE_ONLY: formatString = SR.PnrpCloudResolveOnly; break; case PnrpErrorCodes.WSA_PNRP_FW_PORT_BLOCKED: formatString = SR.PnrpPortBlocked; break; case PnrpErrorCodes.WSA_PNRP_DUPLICATE_PEER_NAME: formatString = SR.PnrpDuplicatePeerName; break; default: formatString = null; break; } if(formatString != null) message = SR.GetString(formatString, cloud); } } internal static class UnsafePnrpNativeMethods { // WSA import functions [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] static extern int WSASetService(CriticalAllocHandle querySet, WsaSetServiceOp essOperation, int dwControlFlags); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] static extern int WSALookupServiceNext(CriticalLookupHandle hLookup, WsaNspControlFlags dwControlFlags, ref int lpdwBufferLength, IntPtr Results); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] static extern int WSALookupServiceEnd(IntPtr hLookup); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] static extern int WSALookupServiceBegin(CriticalAllocHandle query,WsaNspControlFlags dwControlFlags, out CriticalLookupHandle hLookup); [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)] static extern int WSAStartup(Int16 wVersionRequested, ref WsaData lpWSAData); [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)] static extern int WSACleanup(); [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)] static extern int WSAGetLastError(); [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] static extern int WSAEnumNameSpaceProviders(ref int lpdwBufferLength, IntPtr lpnspBuffer); // PNRP namespace identifiers static Guid SvcIdCloud = new Guid(0xc2239ce6, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a); static Guid SvcIdNameV1 = new Guid(0xc2239ce5, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a); static Guid SvcIdName = new Guid(0xc2239ce7, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a); static Guid NsProviderName = new Guid(0x03fe89cd, 0x766d, 0x4976, 0xb9, 0xc1, 0xbb, 0x9b, 0xc4, 0x2c, 0x7b, 0x4d); static Guid NsProviderCloud = new Guid(0x03fe89ce, 0x766d, 0x4976, 0xb9, 0xc1, 0xbb, 0x9b, 0xc4, 0x2c, 0x7b, 0x4d); const int MaxAddresses = 10; const int MaxAddressesV1 = 4; const Int16 RequiredWinsockVersion = 0x0202; // specifies the namespace used used by a specified WSAQUERYSET [Serializable] internal enum NspNamespaces { Cloud = 39, Name = 38, } [Serializable] [Flags] internal enum PnrpCloudFlags { None = 0x0000, LocalName = 0x0001, // Name not valid on other computers } [Serializable] internal enum PnrpCloudState { Virtual = 0, // Not initialized Synchronizing = 1, // The cache is initializing Active = 2, // Cloud is active Dead = 3, // Initialized but lost network Disabled = 4, //disabled in the registry NoNet = 5, //active but lost network Alone = 6, } [Serializable] internal enum PnrpExtendedPayloadType { None = 0, Binary, String } // internal because it is exposed by PeerNameResolver [Serializable] internal enum PnrpResolveCriteria { Default = 0, // Default = PNRP_RESOLVE_CRITERIA_NON_CURRENT_PROCESS_PEER_NAME Remote = 1, // match first 128 bits (remote node) NearestRemote = 2, // match first 128 bits, and close to top 64 bits // of the second 128 bits (remote node) NonCurrentProcess = 3, // match first 128 bits (not in the current process) NearestNonCurrentProcess = 4, // match first 128 bits, and close to top 64 bits // of the second 128 bits (not in the current process) Any = 5, // match first 128 bits (any node) Nearest = 6 // match first 128 bits, and close to top 64 bits // of the second 128 bits (any node) } [Serializable] internal enum PnrpRegisteredIdState { Ok = 1, // Id is active in cloud Problem = 2 // Id is no longer registered in cloud } internal enum PnrpScope { Any = 0, Global = 1, SiteLocal = 2, LinkLocal = 3, } // primary use in this code is to specify what information should be returned by WSALookupServiceNext [Flags] internal enum WsaNspControlFlags { Deep = 0x0001, Containers = 0x0002, NoContainers = 0x0004, Nearest = 0x0008, ReturnName = 0x0010, ReturnType = 0x0020, ReturnVersion = 0x0040, ReturnComment = 0x0080, ReturnAddr = 0x0100, ReturnBlob = 0x0200, ReturnAliases = 0x0400, ReturnQueryString = 0x0800, ReturnAll = 0x0FF0, ResService = 0x8000, FlushCache = 0x1000, FlushPrevious = 0x2000, } internal enum WsaError { WSAEINVAL = 10022, WSAEFAULT = 10014, WSAENOMORE = 10102, WSA_E_NO_MORE = 10110, WSANO_DATA = 11004 } // specifies the operation of WSASetService internal enum WsaSetServiceOp { Register = 0, Deregister, Delete } internal struct BlobSafe { public int cbSize; public CriticalAllocHandle pBlobData; } internal struct BlobNative { public int cbSize; public IntPtr pBlobData; } // PnrpResolver does not currently support any cloud except Global. If this needs to be changed, we will // need to be able to enumerate clouds. // managed equivalent of both PNRPCLOUDINFO and PNRP_CLOUD_ID // internal because it is exposed by PeerCloudEnumerator internal class CloudInfo { public string Name; public PnrpScope Scope; public uint ScopeId; public PnrpCloudState State; public PnrpCloudFlags Flags; } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct CsAddrInfo { public IPEndPoint LocalAddr; public IPEndPoint RemoteAddr; public int iSocketType; public int iProtocol; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal class CsAddrInfoSafe : IDisposable { public SOCKET_ADDRESS_SAFE LocalAddr; public SOCKET_ADDRESS_SAFE RemoteAddr; public int iSocketType; public int iProtocol; bool disposed; public static CsAddrInfoSafe[] FromAddresses(CsAddrInfo[] addresses) { CsAddrInfoSafe addr; CsAddrInfoSafe[] result = null; if(addresses == null || addresses.Length == 0) return null; result = new CsAddrInfoSafe[addresses.Length]; int i=0; foreach(CsAddrInfo info in addresses) { addr = new CsAddrInfoSafe(); addr.LocalAddr = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(info.LocalAddr); addr.RemoteAddr = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(info.RemoteAddr); addr.iProtocol = info.iProtocol; addr.iSocketType = info.iSocketType; result[i++] = addr; } return result; } public static void StructureToPtr(CsAddrInfoSafe input, IntPtr target) { CsAddrInfoNative native; native.iProtocol = input.iProtocol; native.iSocketType = input.iSocketType; native.LocalAddr.iSockaddrLength = input.LocalAddr.iSockaddrLength; native.LocalAddr.lpSockAddr = input.LocalAddr.lpSockAddr; native.RemoteAddr.iSockaddrLength = input.RemoteAddr.iSockaddrLength; native.RemoteAddr.lpSockAddr = input.RemoteAddr.lpSockAddr; Marshal.StructureToPtr(native, target, false); } ~CsAddrInfoSafe() { Dispose(false); } public virtual void Dispose() { Dispose(true); GC.SuppressFinalize(this); } void Dispose(bool disposing) { if(disposed) { if(disposing) { LocalAddr.Dispose(); RemoteAddr.Dispose(); } } disposed = true; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct CsAddrInfoNative { public SOCKET_ADDRESS_NATIVE LocalAddr; public SOCKET_ADDRESS_NATIVE RemoteAddr; public int iSocketType; public int iProtocol; } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct PnrpCloudId { public int AddressFamily; // should be AF_INET6 public PnrpScope Scope; // Global, site, or link public uint ScopeId; // specifies interface } internal struct PnrpCloudInfo { public int dwSize; // size of this struct public PnrpCloudId Cloud; // network cloud information public PnrpCloudState dwCloudState; // state of cloud public PnrpCloudFlags Flags; } //native equivalent for easy marshalling. //should be exactly like PnrpInfo except CriticalHandles internal struct PnrpInfoNative { public int dwSize; // size of this struct public string lpwszIdentity; // identity name string public int nMaxResolve; // number of desired resolutions public int dwTimeout; // time in seconds to wait for responses public int dwLifetime; // time in seconds for validity public PnrpResolveCriteria enResolveCriteria; // criteria for resolve matches public int dwFlags; // set of flags public SOCKET_ADDRESS_NATIVE saHint; // IPv6 addr use for location public PnrpRegisteredIdState enNameState; // state of registered name } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct PnrpInfo { public int dwSize; // size of this struct public string lpwszIdentity; // identity name string public int nMaxResolve; // number of desired resolutions public int dwTimeout; // time in seconds to wait for responses public int dwLifetime; // time in seconds for validity public PnrpResolveCriteria enResolveCriteria; // criteria for resolve matches public int dwFlags; // set of flags public SOCKET_ADDRESS_SAFE saHint; // IPv6 addr use for location public PnrpRegisteredIdState enNameState; // state of registered name public static void ToPnrpInfoNative(PnrpInfo source, ref PnrpInfoNative target) { target.dwSize = source.dwSize; target.lpwszIdentity = source.lpwszIdentity; target.nMaxResolve = source.nMaxResolve; target.dwTimeout = source.dwTimeout; target.dwLifetime = source.dwLifetime; target.enResolveCriteria = source.enResolveCriteria; target.dwFlags = source.dwFlags; if (source.saHint != null) { target.saHint.lpSockAddr = source.saHint.lpSockAddr; target.saHint.iSockaddrLength = source.saHint.iSockaddrLength; } else { target.saHint.lpSockAddr = IntPtr.Zero; target.saHint.iSockaddrLength = 0; } target.enNameState = source.enNameState; } } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct sockaddr_in { public short sin_family; public ushort sin_port; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] sin_addr; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] sin_zero; } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct sockaddr_in6 { public short sin6_family; public ushort sin6_port; public uint sin6_flowinfo; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] sin6_addr; public uint sin6_scope_id; } internal class SOCKET_ADDRESS_SAFE : IDisposable { public CriticalAllocHandle lpSockAddr; public int iSockaddrLength; bool disposed; public static SOCKET_ADDRESS_SAFE SocketAddressFromIPEndPoint(IPEndPoint endpoint) { SOCKET_ADDRESS_SAFE socketAddress = new SOCKET_ADDRESS_SAFE(); if (endpoint == null) return socketAddress; if (endpoint.AddressFamily == AddressFamily.InterNetwork) { socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in)); socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength); sockaddr_in sa = new sockaddr_in(); sa.sin_family = (short)AddressFamily.InterNetwork; sa.sin_port = (ushort)endpoint.Port; sa.sin_addr = endpoint.Address.GetAddressBytes(); Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false); } else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6) { socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in6)); socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength); sockaddr_in6 sa = new sockaddr_in6(); sa.sin6_family = (short)AddressFamily.InterNetworkV6; sa.sin6_port = (ushort)endpoint.Port; sa.sin6_addr = endpoint.Address.GetAddressBytes(); sa.sin6_scope_id = (uint)endpoint.Address.ScopeId; Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false); } return socketAddress; } ~SOCKET_ADDRESS_SAFE() { Dispose(false); } public virtual void Dispose() { Dispose(true); GC.SuppressFinalize(this); } void Dispose(bool disposing) { if(!disposed) { if(disposing) lpSockAddr.Dispose(); } disposed = true; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct SOCKET_ADDRESS_NATIVE { public IntPtr lpSockAddr; public int iSockaddrLength; } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal struct WsaData { public Int16 wVersion; public Int16 wHighVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szSystemStatus; public Int16 iMaxSockets; public Int16 iMaxUdpDg; public IntPtr lpVendorInfo; } [Serializable] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct WsaNamespaceInfo { public Guid NSProviderId; public int dwNameSpace; public int fActive; public int dwVersion; // don't bother marshalling this as a string since we don't need to look at it public IntPtr lpszIdentifier; } // managed equivalent of WSAQUERYSET internal class WsaQuerySet { public string ServiceInstanceName; public Guid ServiceClassId; public string Comment; public NspNamespaces NameSpace; public Guid NSProviderId; public string Context; public CsAddrInfo[] CsAddrInfos; public object Blob; static public WsaQuerySetSafe ToWsaQuerySetSafe(WsaQuerySet input) { WsaQuerySetSafe result = new WsaQuerySetSafe(); if(input == null) return result; result.dwSize = Marshal.SizeOf(typeof(WsaQuerySetNative)); result.lpszServiceInstanceName = CriticalAllocHandleString.FromString(input.ServiceInstanceName); result.lpServiceClassId = CriticalAllocHandleGuid.FromGuid(input.ServiceClassId); result.lpszComment = CriticalAllocHandleString.FromString(input.Comment); result.dwNameSpace = input.NameSpace; result.lpNSProviderId = CriticalAllocHandleGuid.FromGuid(input.NSProviderId); result.lpszContext = CriticalAllocHandleString.FromString(input.Context); result.dwNumberOfProtocols = 0; result.lpafpProtocols = IntPtr.Zero; // not used result.lpszQueryString = IntPtr.Zero; if (input.CsAddrInfos != null) { result.dwNumberOfCsAddrs = input.CsAddrInfos.Length; result.addressList = CsAddrInfoSafe.FromAddresses(input.CsAddrInfos); } result.dwOutputFlags = 0; result.lpBlob = CriticalAllocHandlePnrpBlob.FromPnrpBlob(input.Blob); return result; } } internal class CriticalAllocHandlePnrpBlob : CriticalAllocHandle { public static CriticalAllocHandle FromPnrpBlob(object input) { BlobSafe blob = new BlobSafe(); if (input != null) { if (input.GetType() == typeof(PnrpInfo)) { int blobSize = Marshal.SizeOf(typeof(PnrpInfoNative)); blob.pBlobData = CriticalAllocHandle.FromSize(blobSize + Marshal.SizeOf(typeof(BlobNative))); //write the BlobSafe fields first, BlobNative nativeBlob; nativeBlob.cbSize = blobSize; nativeBlob.pBlobData = (IntPtr)(((IntPtr)blob.pBlobData).ToInt64()+Marshal.SizeOf(typeof(BlobNative))); Marshal.StructureToPtr(nativeBlob,(IntPtr)blob.pBlobData,false); PnrpInfo pnrpInfo = (PnrpInfo)input; pnrpInfo.dwSize = blobSize; PnrpInfoNative nativeInfo = new PnrpInfoNative(); PnrpInfo.ToPnrpInfoNative(pnrpInfo, ref nativeInfo); Marshal.StructureToPtr(nativeInfo, (IntPtr)nativeBlob.pBlobData, false); blob.cbSize = blobSize; } else if(input.GetType() == typeof(PnrpCloudInfo)) { int blobSize = Marshal.SizeOf(input.GetType()); blob.pBlobData = CriticalAllocHandle.FromSize(blobSize + Marshal.SizeOf(typeof(BlobNative))); //write the BlobSafe fields first, BlobNative nativeBlob; nativeBlob.cbSize = blobSize; nativeBlob.pBlobData = (IntPtr)(((IntPtr)blob.pBlobData).ToInt64()+Marshal.SizeOf(typeof(BlobNative))); Marshal.StructureToPtr(nativeBlob,(IntPtr)blob.pBlobData,false); PnrpCloudInfo cloudInfo = (PnrpCloudInfo)input; cloudInfo.dwSize = Marshal.SizeOf(typeof(PnrpCloudInfo)); Marshal.StructureToPtr(cloudInfo, (IntPtr)nativeBlob.pBlobData,false); blob.cbSize = blobSize; } else { DiagnosticUtility.DebugAssert("Unknown payload type!"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } return blob.pBlobData; } } internal class CriticalAllocHandleString : CriticalAllocHandle { public static CriticalAllocHandle FromString(string input) { CriticalAllocHandleString result = new CriticalAllocHandleString(); RuntimeHelpers.PrepareConstrainedRegions(); try{} finally { result.SetHandle(Marshal.StringToHGlobalUni(input)); } return result; } } internal class CriticalAllocHandleWsaQuerySetSafe : CriticalAllocHandle { static int CalculateSize(WsaQuerySetSafe safeQuerySet) { int structSize = Marshal.SizeOf(typeof(WsaQuerySetNative)); if(safeQuerySet.addressList != null) structSize += safeQuerySet.addressList.Length * Marshal.SizeOf(typeof(CsAddrInfoNative)); return structSize; } public static CriticalAllocHandle FromWsaQuerySetSafe(WsaQuerySetSafe safeQuerySet) { CriticalAllocHandle result = CriticalAllocHandle.FromSize(CalculateSize(safeQuerySet)); WsaQuerySetSafe.StructureToPtr(safeQuerySet, (IntPtr)result); return result; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal class WsaQuerySetSafe : IDisposable { public int dwSize; public CriticalAllocHandle lpszServiceInstanceName; public CriticalAllocHandle lpServiceClassId; public IntPtr lpVersion; // not used public CriticalAllocHandle lpszComment; public NspNamespaces dwNameSpace; public CriticalAllocHandle lpNSProviderId; public CriticalAllocHandle lpszContext; public int dwNumberOfProtocols; // 0 public IntPtr lpafpProtocols; // not used public IntPtr lpszQueryString; // not used public int dwNumberOfCsAddrs; public CsAddrInfoSafe[] addressList; public int dwOutputFlags; // 0 public CriticalAllocHandle lpBlob; bool disposed; ~WsaQuerySetSafe() { Dispose(false); } public virtual void Dispose() { Dispose(true); GC.SuppressFinalize(this); } void Dispose(bool disposing) { if(!disposed) { if(disposing) { if(lpszServiceInstanceName != null) lpszServiceInstanceName.Dispose(); if(lpServiceClassId != null) lpServiceClassId.Dispose(); if(lpszComment != null) lpszComment.Dispose(); if(lpNSProviderId != null) lpNSProviderId.Dispose(); if(lpBlob != null) lpBlob.Dispose(); if(addressList != null) { foreach(CsAddrInfoSafe addr in addressList) { addr.Dispose(); } } } } disposed = true; } static public void StructureToPtr(WsaQuerySetSafe input, IntPtr target) { WsaQuerySetNative native = new WsaQuerySetNative(); native.dwSize = input.dwSize; native.lpszServiceInstanceName = input.lpszServiceInstanceName; native.lpServiceClassId = input.lpServiceClassId; native.lpVersion = IntPtr.Zero; // not used native.lpszComment = input.lpszComment; native.dwNameSpace = input.dwNameSpace; native.lpNSProviderId = input.lpNSProviderId; native.lpszContext = input.lpszContext; native.dwNumberOfProtocols = 0; // 0 native.lpafpProtocols = IntPtr.Zero; // not used native.lpszQueryString = IntPtr.Zero; // not used native.dwNumberOfCsAddrs = input.dwNumberOfCsAddrs; native.dwOutputFlags = 0; // 0 native.lpBlob = input.lpBlob; Int64 sockAddressStart = target.ToInt64()+Marshal.SizeOf(typeof(WsaQuerySetNative)); native.lpcsaBuffer = (IntPtr)sockAddressStart; Marshal.StructureToPtr(native, target, false); MarshalSafeAddressesToNative(input,(IntPtr)sockAddressStart); } public static void MarshalSafeAddressesToNative(WsaQuerySetSafe safeQuery, IntPtr target) { // marshal the addresses if (safeQuery.addressList != null && safeQuery.addressList.Length > 0) { int sizeOfCsAddrInfo = Marshal.SizeOf(typeof(CsAddrInfoNative)); Int64 start = target.ToInt64(); DiagnosticUtility.DebugAssert(start%IntPtr.Size == 0, "Invalid alignment!!"); foreach(CsAddrInfoSafe safeAddress in safeQuery.addressList) { CsAddrInfoSafe.StructureToPtr(safeAddress,(IntPtr)start); start += sizeOfCsAddrInfo; } } } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct WsaQuerySetNative { public int dwSize; public IntPtr lpszServiceInstanceName; public IntPtr lpServiceClassId; public IntPtr lpVersion; // not used public IntPtr lpszComment; public NspNamespaces dwNameSpace; public IntPtr lpNSProviderId; public IntPtr lpszContext; public int dwNumberOfProtocols; // 0 public IntPtr lpafpProtocols; // not used public IntPtr lpszQueryString; // not used public int dwNumberOfCsAddrs; public IntPtr lpcsaBuffer; public int dwOutputFlags; // 0 public IntPtr lpBlob; } internal class CriticalLookupHandle : CriticalHandleZeroOrMinusOneIsInvalid { protected override bool ReleaseHandle() { return WSALookupServiceEnd(handle) == 0; } } // base class for ref-counting WSA uses and calling WSAStartup/WSAShutdown internal class DiscoveryBase : MarshalByRefObject, IDisposable { static int refCount = 0; static object refCountLock = new object(); bool disposed; public DiscoveryBase() { lock (refCountLock) { if (refCount == 0) { WsaData WinsockVersion = new WsaData(); int ret = WSAStartup(UnsafePnrpNativeMethods.RequiredWinsockVersion, ref WinsockVersion); if (ret != 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException(ret)); } } refCount++; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose(bool disposing) { if(!disposed) { lock (refCountLock) { refCount--; if (refCount == 0) { WSACleanup(); } } } disposed = true; } ~DiscoveryBase() { this.Dispose(false); } public bool IsPnrpServiceRunning(TimeSpan waitForService) { TimeoutHelper timeoutHelper = new TimeoutHelper(waitForService); try { using (ServiceController sc = new ServiceController("pnrpsvc")) { try { if(sc.Status == ServiceControllerStatus.StopPending) { sc.WaitForStatus(ServiceControllerStatus.Stopped, timeoutHelper.RemainingTime()); } if(sc.Status == ServiceControllerStatus.Stopped) { sc.Start(); } sc.WaitForStatus(ServiceControllerStatus.Running, timeoutHelper.RemainingTime()); } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; if(e is InvalidOperationException || e is TimeoutException) return false; else throw; } return (sc.Status == ServiceControllerStatus.Running); } } catch(InvalidOperationException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); DiagnosticUtility.DebugAssert("IsPnrpServiceRunning should be called after IsPnrpInstalled"); return false; } } public bool IsPnrpAvailable(TimeSpan waitForService) { if (!IsPnrpInstalled()) return false; //make sure that the service is running if (!IsPnrpServiceRunning(waitForService)) return false; // If PNRP is installed, ensure that it supports extended payload by attempting to register with // an invalid query set. If extended payload is not available, "WSASERVICE_NOT_FOUND" is returned. // Otherwise, "WSAEINVAL" is returned. //UPDATE: we will work with PNRP 1.0 if it is available. // a separate implementation will work with payload support when available. WsaQuerySet querySet = new WsaQuerySet(); querySet.NSProviderId = NsProviderName; querySet.ServiceClassId = SvcIdNameV1; int res = InvokeService(querySet, WsaSetServiceOp.Register,0); //on xp 64bit, WSANO_DATA is returned if (res == (int)WsaError.WSAEINVAL || res == (int)WsaError.WSANO_DATA) return true; // if the call didn't fail or returned any other error, PNRP clearly isn't working properly return false; } // determine if any version of PNRP is installed and available public bool IsPnrpInstalled() { int size = 0; int nProviders; CriticalAllocHandle dataPtr = null; // retrieve the list of installed namespace providers // implemented in a loop in case the size changes between the first and second calls while (true) { nProviders = WSAEnumNameSpaceProviders(ref size, (IntPtr)dataPtr); if (nProviders != -1) // success break; int error = WSAGetLastError(); if (error != (int)WsaError.WSAEFAULT) // buffer length to small return false; // any other error effectively means that PNRP isn't usable dataPtr = CriticalAllocHandle.FromSize(size); } // loop through the providers for (int i = 0; i < nProviders; i++) { IntPtr nsInfoPtr = (IntPtr)(((IntPtr)dataPtr).ToInt64() + i * Marshal.SizeOf(typeof(WsaNamespaceInfo))); WsaNamespaceInfo nsInfo = (WsaNamespaceInfo)Marshal.PtrToStructure(nsInfoPtr, typeof(WsaNamespaceInfo)); // if this is the PNRP name namespace provider and it is active, it is installed if (nsInfo.NSProviderId == NsProviderName && nsInfo.fActive != 0) return true; } // no PNRP name namespace provider found return false; } int InvokeService(WsaQuerySet registerQuery, WsaSetServiceOp op, int flags) { WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(registerQuery); int error = 0; using (native) { CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); using(handle) { int retval = WSASetService(handle, op, flags); if (retval != 0) { error = WSAGetLastError(); } } } return error; } } public class PeerCloudEnumerator : DiscoveryBase { static public CloudInfo[] GetClouds() { int retval = 0; ArrayList clouds = new ArrayList(); WsaQuerySet querySet = new WsaQuerySet(); CriticalLookupHandle hLookup; PnrpCloudInfo cloudInfo = new PnrpCloudInfo(); cloudInfo.dwSize = Marshal.SizeOf(typeof(PnrpCloudInfo)); cloudInfo.Cloud.Scope = PnrpScope.Any; cloudInfo.dwCloudState = (PnrpCloudState)0; cloudInfo.Flags = PnrpCloudFlags.None; querySet.NameSpace = NspNamespaces.Cloud; querySet.NSProviderId = NsProviderCloud; querySet.ServiceClassId = SvcIdCloud; querySet.Blob = cloudInfo; WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(querySet); using(native) { CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); retval = WSALookupServiceBegin(handle, WsaNspControlFlags.ReturnAll, out hLookup); } if (retval != 0) { // unable to start the enumeration SocketException exception = new SocketException(WSAGetLastError()); Utility.CloseInvalidOutCriticalHandle(hLookup); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception); } // start with a sensible default size int size = Marshal.SizeOf(typeof(WsaQuerySetSafe)) + 200; //wrap in CriticalAllocHandle when PAYLOAD is enabled CriticalAllocHandle nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); using(hLookup) { while (true) { retval = WSALookupServiceNext(hLookup, 0, ref size, (IntPtr)nativeQuerySetPtr); if (retval != 0) { int error = WSAGetLastError(); if (error == (int)WsaError.WSAENOMORE || error == (int)WsaError.WSA_E_NO_MORE) { // no more break; } if (error == (int)WsaError.WSAEFAULT) { // buffer too small, allocate a bigger one of the specified size if(nativeQuerySetPtr != null) { nativeQuerySetPtr.Dispose(); nativeQuerySetPtr = null; } //wrap in CriticalAllocHandle when PAYLOAD is enabled nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); continue; } // unexpected error throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException(error)); } else { if (nativeQuerySetPtr != IntPtr.Zero) { // marshal the results into something usable WsaQuerySet resultQuerySet = PeerNameResolver.MarshalWsaQuerySetNativeToWsaQuerySet(nativeQuerySetPtr,0); // extract out the friendly cloud attributes CloudInfo resultCloudInfo = new CloudInfo(); PnrpCloudInfo prnpCloudInfo = (PnrpCloudInfo)resultQuerySet.Blob; resultCloudInfo.Name = resultQuerySet.ServiceInstanceName; resultCloudInfo.Scope = prnpCloudInfo.Cloud.Scope; resultCloudInfo.ScopeId = prnpCloudInfo.Cloud.ScopeId; resultCloudInfo.State = prnpCloudInfo.dwCloudState; resultCloudInfo.Flags = prnpCloudInfo.Flags; // add it to the list to return later clouds.Add(resultCloudInfo); } } } } // package up the results into a nice array return (CloudInfo[])clouds.ToArray(typeof(CloudInfo)); } } internal class PeerNameRegistrar : DiscoveryBase { const int RegistrationLifetime = 60 * 60; // 1 hour public PeerNameRegistrar() : base() { } public void Register(PnrpRegistration registration, TimeSpan timeout) { // fill in the PnrpInfo blob using the defaults PnrpInfo pnrpInfo = new PnrpInfo(); pnrpInfo.dwLifetime = RegistrationLifetime; pnrpInfo.lpwszIdentity = null; pnrpInfo.dwSize = Marshal.SizeOf(pnrpInfo); pnrpInfo.dwFlags = PNRPINFO_HINT; IPEndPoint hint = PnrpPeerResolver.GetHint(); pnrpInfo.saHint = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(hint); // fill in the query set WsaQuerySet registerQuery = new WsaQuerySet(); registerQuery.NameSpace = NspNamespaces.Name; registerQuery.NSProviderId = NsProviderName; registerQuery.ServiceClassId = SvcIdNameV1; registerQuery.ServiceInstanceName = registration.PeerName; registerQuery.Comment = registration.Comment; registerQuery.Context = registration.CloudName; // copy over the addresses if (registration.Addresses != null) { DiagnosticUtility.DebugAssert(registration.Addresses.Length <= 4, "Pnrp supports only 4 addresses"); registerQuery.CsAddrInfos = new CsAddrInfo[registration.Addresses.Length]; for (int i = 0; i < registration.Addresses.Length; i++) { // the only interesting part of the CsAddrInfo is the LocalAddress registerQuery.CsAddrInfos[i].LocalAddr = registration.Addresses[i]; registerQuery.CsAddrInfos[i].iProtocol = (int)ProtocolType.Tcp; registerQuery.CsAddrInfos[i].iSocketType = (int)SocketType.Stream; } } // copy the blob registerQuery.Blob = pnrpInfo; RegisterService(registerQuery); } public void Unregister(string peerName, List clouds, TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); foreach(string cloud in clouds) { try { Unregister(peerName, cloud, timeoutHelper.RemainingTime()); } catch(SocketException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } } public void Unregister(string peerName, string cloudName, TimeSpan timeout) { // fill in the PnrpInfo with defaults PnrpInfo identityInfo = new PnrpInfo(); identityInfo.lpwszIdentity = null; identityInfo.dwSize = Marshal.SizeOf(typeof(PnrpInfo)); // fill in the query set WsaQuerySet registerQuery = new WsaQuerySet(); registerQuery.NameSpace = NspNamespaces.Name; registerQuery.NSProviderId = NsProviderName; registerQuery.ServiceClassId = SvcIdNameV1; registerQuery.ServiceInstanceName = peerName; registerQuery.Context = cloudName; registerQuery.Blob = identityInfo; DeleteService(registerQuery); } void RegisterService(WsaQuerySet registerQuery) { try { InvokeService(registerQuery, WsaSetServiceOp.Register, 0); } catch(PnrpException) { if(PnrpPeerResolver.MaxAddressEntriesV1 < registerQuery.CsAddrInfos.Length) { List infos = new List (registerQuery.CsAddrInfos); infos.RemoveRange(PnrpPeerResolver.MaxAddressEntriesV1, registerQuery.CsAddrInfos.Length-PnrpPeerResolver.MaxAddressEntriesV1); registerQuery.CsAddrInfos = infos.ToArray(); InvokeService(registerQuery, WsaSetServiceOp.Register, 0); } else throw; } } void DeleteService(WsaQuerySet registerQuery) { InvokeService(registerQuery, WsaSetServiceOp.Delete, 0); } static void InvokeService(WsaQuerySet registerQuery, WsaSetServiceOp op, int flags) { WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(registerQuery); using(native) { CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); int retval = WSASetService(handle, op, flags); if (retval != 0) { int error = WSAGetLastError(); PeerExceptionHelper.ThrowPnrpError(error, registerQuery.Context); } } } } internal class PeerNameResolver : AsyncResult //: DiscoveryBase { WsaQuerySet resolveQuery; List results; uint scopeId; Exception lastException; TimeoutHelper timeoutHelper; public PeerNameResolver(string peerName, int numberOfResultsRequested, PnrpResolveCriteria resolveCriteria, TimeSpan timeout, List results) : this(peerName, numberOfResultsRequested, resolveCriteria, 0, GlobalCloudName, timeout, results) { } public PeerNameResolver(string peerName, int numberOfResultsRequested, PnrpResolveCriteria resolveCriteria, uint scopeId, string cloudName, TimeSpan timeout, List results) : base(null,null) { // pnrp has a hard-coded limit on the timeout value that can be passed to it // maximum value is 10 minutes if (timeout > MaxTimeout) { timeout = MaxTimeout; } timeoutHelper = new TimeoutHelper(timeout); PnrpInfo resolveQueryInfo = new PnrpInfo(); resolveQueryInfo.dwSize = Marshal.SizeOf(typeof(PnrpInfo)); resolveQueryInfo.nMaxResolve = numberOfResultsRequested; resolveQueryInfo.dwTimeout = (int)timeout.TotalSeconds; resolveQueryInfo.dwLifetime = 0; resolveQueryInfo.enNameState = 0; resolveQueryInfo.lpwszIdentity = null; resolveQueryInfo.dwFlags = PNRPINFO_HINT; IPEndPoint hint = PnrpPeerResolver.GetHint(); resolveQueryInfo.enResolveCriteria = resolveCriteria ; resolveQueryInfo.saHint = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(hint); resolveQuery = new WsaQuerySet(); resolveQuery.ServiceInstanceName = peerName; resolveQuery.ServiceClassId = SvcIdNameV1; resolveQuery.NameSpace = NspNamespaces.Name; resolveQuery.NSProviderId = NsProviderName; resolveQuery.Context = cloudName; resolveQuery.Blob = resolveQueryInfo; this.results = results; this.scopeId = scopeId; IOThreadScheduler.ScheduleCallback(new WaitCallback(SyncEnumeration),null); } public void End() { AsyncResult.End (this); } public void SyncEnumeration(object state) { int retval = 0; CriticalLookupHandle hLookup; WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(resolveQuery); using(native) { CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); retval = WSALookupServiceBegin(handle, WsaNspControlFlags.ReturnAll, out hLookup); } if (retval != 0) { lastException = new PnrpException(WSAGetLastError(), resolveQuery.Context); Utility.CloseInvalidOutCriticalHandle(hLookup); Complete(false,lastException); return; } WsaQuerySet querySet = new WsaQuerySet(); // start with a sensible default size int size = Marshal.SizeOf(typeof(WsaQuerySetSafe)) + 400; CriticalAllocHandle nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); try { using(hLookup) { while (true) { if (timeoutHelper.RemainingTime() == TimeSpan.Zero) { break; } retval = WSALookupServiceNext(hLookup, 0, ref size, (IntPtr)nativeQuerySetPtr); if (retval != 0) { int error = WSAGetLastError(); if (error == (int)WsaError.WSAENOMORE || error == (int)WsaError.WSA_E_NO_MORE) { // no more break; } if (error == (int)WsaError.WSAEFAULT) { nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); continue; } // unexpected error PeerExceptionHelper.ThrowPnrpError(error, querySet.Context); } else { if (nativeQuerySetPtr != IntPtr.Zero) { // marshal the results into something useful querySet = MarshalWsaQuerySetNativeToWsaQuerySet(nativeQuerySetPtr,scopeId); // allocate the friendly PnrpRegistration and fill it in PnrpRegistration pnrpRegistration = new PnrpRegistration(); pnrpRegistration.CloudName = querySet.Context; pnrpRegistration.Comment = querySet.Comment; pnrpRegistration.PeerName = querySet.ServiceInstanceName; pnrpRegistration.Addresses = new IPEndPoint[querySet.CsAddrInfos.Length]; for (int i = 0; i < querySet.CsAddrInfos.Length; i++) pnrpRegistration.Addresses[i] = querySet.CsAddrInfos[i].LocalAddr; // add it to the list to return later. // all cloud enumeratos in the same scope will reference the same list and hence the lock. lock (results) { results.Add(pnrpRegistration); } } } } } } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); if (DiagnosticUtility.ShouldTraceInformation) { PnrpResolveExceptionTraceRecord record = new PnrpResolveExceptionTraceRecord(resolveQuery.ServiceInstanceName,resolveQuery.Context,e); if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.PnrpResolveException, record, this, null); } } lastException = e; } finally { Complete(false, lastException); } } static internal WsaQuerySet MarshalWsaQuerySetNativeToWsaQuerySet(IntPtr pNativeData) { return MarshalWsaQuerySetNativeToWsaQuerySet(pNativeData,0); } static internal WsaQuerySet MarshalWsaQuerySetNativeToWsaQuerySet(IntPtr pNativeData, uint scopeId) { if (pNativeData == IntPtr.Zero) return null; WsaQuerySet querySet = new WsaQuerySet(); // build a native structure from the raw memory WsaQuerySetNative nativeQuerySet; nativeQuerySet = (WsaQuerySetNative)Marshal.PtrToStructure(pNativeData, typeof(WsaQuerySetNative)); CsAddrInfoNative nativeCsAddrInfo; int sizeOfCsAddrInfo = Marshal.SizeOf(typeof(CsAddrInfoNative)); // copy over the simple fields querySet.Context = Marshal.PtrToStringUni(nativeQuerySet.lpszContext); querySet.NameSpace = nativeQuerySet.dwNameSpace; querySet.ServiceInstanceName = Marshal.PtrToStringUni(nativeQuerySet.lpszServiceInstanceName); querySet.Comment = Marshal.PtrToStringUni(nativeQuerySet.lpszComment); // copy the addresses querySet.CsAddrInfos = new CsAddrInfo[nativeQuerySet.dwNumberOfCsAddrs]; for (int i = 0; i < nativeQuerySet.dwNumberOfCsAddrs; i++) { IntPtr addressPtr = (IntPtr)(nativeQuerySet.lpcsaBuffer.ToInt64() + (i * sizeOfCsAddrInfo)); nativeCsAddrInfo = (CsAddrInfoNative)Marshal.PtrToStructure(addressPtr, typeof(CsAddrInfoNative)); querySet.CsAddrInfos[i].iProtocol = nativeCsAddrInfo.iProtocol; querySet.CsAddrInfos[i].iSocketType = nativeCsAddrInfo.iSocketType; querySet.CsAddrInfos[i].LocalAddr = IPEndPointFromSocketAddress(nativeCsAddrInfo.LocalAddr,scopeId); querySet.CsAddrInfos[i].RemoteAddr = IPEndPointFromSocketAddress(nativeCsAddrInfo.RemoteAddr,scopeId); } // copy the GUIDs if (nativeQuerySet.lpNSProviderId != IntPtr.Zero) querySet.NSProviderId = (Guid)Marshal.PtrToStructure(nativeQuerySet.lpNSProviderId, typeof(Guid)); if (nativeQuerySet.lpServiceClassId != IntPtr.Zero) querySet.ServiceClassId = (Guid)Marshal.PtrToStructure(nativeQuerySet.lpServiceClassId, typeof(Guid)); // marshal the BLOB according to namespace if (querySet.NameSpace == NspNamespaces.Cloud) { if (nativeQuerySet.lpBlob != IntPtr.Zero) { // give it a default value querySet.Blob = new PnrpCloudInfo(); // marshal the blob in order to get the pointer BlobNative blob = (BlobNative)Marshal.PtrToStructure(nativeQuerySet.lpBlob, typeof(BlobNative)); // marshal the actual PnrpCloudInfo if (blob.pBlobData != IntPtr.Zero) querySet.Blob = (PnrpCloudInfo)Marshal.PtrToStructure(blob.pBlobData, typeof(PnrpCloudInfo)); } } else if (querySet.NameSpace == NspNamespaces.Name) { if (nativeQuerySet.lpBlob != IntPtr.Zero) { // give it a default value querySet.Blob = new PnrpInfo(); // marshal the blob in order to get the pointer BlobSafe blob = (BlobSafe)Marshal.PtrToStructure(nativeQuerySet.lpBlob, typeof(BlobSafe)); // marshal the actual PnrpInfo if (blob.pBlobData != IntPtr.Zero) { PnrpInfo pnrpInfo = (PnrpInfo)Marshal.PtrToStructure(blob.pBlobData, typeof(PnrpInfo)); querySet.Blob = pnrpInfo; } } } return querySet; } static IPEndPoint IPEndPointFromSocketAddress(SOCKET_ADDRESS_NATIVE socketAddress, uint scopeId) { IPEndPoint endPoint = null; if (socketAddress.lpSockAddr != IntPtr.Zero) { AddressFamily addressFamily = (AddressFamily)Marshal.ReadInt16(socketAddress.lpSockAddr); if (addressFamily == AddressFamily.InterNetwork) { // if the sockaddr length is not the sizeof(sockaddr_in), the data is invalid so // return an null endpoint if (socketAddress.iSockaddrLength == Marshal.SizeOf(typeof(sockaddr_in))) { sockaddr_in sa = (sockaddr_in)Marshal.PtrToStructure(socketAddress.lpSockAddr, typeof(sockaddr_in)); endPoint = new IPEndPoint(new IPAddress(sa.sin_addr), sa.sin_port); } } else if (addressFamily == AddressFamily.InterNetworkV6) { // if the sockaddr length is not the sizeof(sockaddr_in6), the data is invalid so // return an null endpoint if (socketAddress.iSockaddrLength == Marshal.SizeOf(typeof(sockaddr_in6))) { sockaddr_in6 sa = (sockaddr_in6)Marshal.PtrToStructure(socketAddress.lpSockAddr, typeof(sockaddr_in6)); if(scopeId != 0 && sa.sin6_scope_id != 0) scopeId = sa.sin6_scope_id; endPoint = new IPEndPoint(new IPAddress(sa.sin6_addr, scopeId), sa.sin6_port); } } // else this is an unknown address family, so return null } return endPoint; } } } public override bool Equals(object other) { return ((other as PnrpPeerResolver) != null); } public override int GetHashCode() { return base.GetHashCode(); } } } // 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
- FindResponse.cs
- SmiMetaDataProperty.cs
- Int32Storage.cs
- CodeVariableDeclarationStatement.cs
- MarshalDirectiveException.cs
- JsonStringDataContract.cs
- EncoderParameter.cs
- TextBox.cs
- ExpressionContext.cs
- StatusBarPanelClickEvent.cs
- BooleanStorage.cs
- FontStretches.cs
- TrustSection.cs
- HttpRequestCacheValidator.cs
- BitmapEffectDrawingContent.cs
- EtwTrace.cs
- XPathEmptyIterator.cs
- DataGridColumnHeader.cs
- SystemNetworkInterface.cs
- TextChange.cs
- AnimationStorage.cs
- RunClient.cs
- QueryTask.cs
- XmlILOptimizerVisitor.cs
- MultiPropertyDescriptorGridEntry.cs
- Byte.cs
- ApplicationFileCodeDomTreeGenerator.cs
- ISCIIEncoding.cs
- TagPrefixInfo.cs
- WebZone.cs
- XsltOutput.cs
- HttpCachePolicyWrapper.cs
- ToolStripSeparator.cs
- ReadOnlyObservableCollection.cs
- CheckedPointers.cs
- NotifyIcon.cs
- MessageQueueAccessControlEntry.cs
- SharedPerformanceCounter.cs
- xml.cs
- CopyOnWriteList.cs
- DateTimeEditor.cs
- ToolStripContainer.cs
- MessageBox.cs
- EditCommandColumn.cs
- IISUnsafeMethods.cs
- QilLoop.cs
- MarkupCompiler.cs
- UDPClient.cs
- AvTrace.cs
- AppSettingsReader.cs
- InternalResources.cs
- ChainOfResponsibility.cs
- BinarySerializer.cs
- CopyAction.cs
- login.cs
- RuntimeWrappedException.cs
- PersonalizationStateQuery.cs
- SelectionRangeConverter.cs
- ItemChangedEventArgs.cs
- AnnotationResource.cs
- WorkflowMarkupSerializationException.cs
- SliderAutomationPeer.cs
- InputProcessorProfiles.cs
- KerberosRequestorSecurityTokenAuthenticator.cs
- HttpServerVarsCollection.cs
- CompiledQueryCacheEntry.cs
- BamlRecords.cs
- SettingsPropertyNotFoundException.cs
- ServiceDiscoveryElement.cs
- DataSetMappper.cs
- UnauthorizedWebPart.cs
- RightsManagementPermission.cs
- WsatAdminException.cs
- DesignObjectWrapper.cs
- BlockExpression.cs
- PackagingUtilities.cs
- Privilege.cs
- BaseCodePageEncoding.cs
- HtmlHead.cs
- ListViewDeletedEventArgs.cs
- WebPermission.cs
- ComMethodElement.cs
- SchemaElement.cs
- MultipartContentParser.cs
- ScriptComponentDescriptor.cs
- BCLDebug.cs
- X509IssuerSerialKeyIdentifierClause.cs
- XmlLanguageConverter.cs
- GlyphInfoList.cs
- ReadOnlyActivityGlyph.cs
- MenuCommand.cs
- FileSystemInfo.cs
- SponsorHelper.cs
- ByteStack.cs
- BindableTemplateBuilder.cs
- RuleSettingsCollection.cs
- VirtualDirectoryMappingCollection.cs
- EncryptedKey.cs
- PowerStatus.cs
- ScriptReferenceBase.cs