We need you! We're working hard on the next version of Developer Fusion - Let us know what you think we should be up to!

The Labs \ Source Viewer \ SSCLI \ System.Net \ Blob

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Internal.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Net
  16. {
  17.     using System.IO;
  18.     using System.Reflection;
  19.     using System.Collections;
  20.     using System.Collections.Generic;
  21.     using System.Collections.Specialized;
  22.     using System.Globalization;
  23.     using System.Net.Sockets;
  24.     using System.Runtime.InteropServices;
  25.     using System.Runtime.Versioning;
  26.     using System.Security.Cryptography.X509Certificates;
  27.     using System.Text;
  28.     using System.Text.RegularExpressions;
  29.     using System.Security.Permissions;
  30.     using System.Diagnostics;
  31.     using System.Threading;
  32.     using System.Security.Principal;
  33.     using System.Security;
  34.     using System.Net.Security;
  35.     using System.Net.NetworkInformation;
  36.     using System.Runtime.Serialization;
  37.    
  38.     static internal class IntPtrHelper
  39.     {
  40. /*
  41.         //                                   
  42.         internal static IntPtr Add(IntPtr a, IntPtr b) {
  43.             return (IntPtr) ((long)a + (long)b);
  44.         }
  45.         */       
  46.         static internal IntPtr Add(IntPtr a, int b)
  47.         {
  48.             return (IntPtr)((long)a + (long)b);
  49.         }
  50.     }
  51.    
  52.     internal class InternalException : SystemException
  53.     {
  54.         internal InternalException()
  55.         {
  56.             GlobalLog.Assert("InternalException thrown.");
  57.         }
  58.        
  59.         internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
  60.         {
  61.         }
  62.     }
  63.    
  64.     static internal class NclUtilities
  65.     {
  66.         /// <devdoc>
  67.         /// <para>
  68.         /// Indicates true if the threadpool is low on threads,
  69.         /// in this case we need to refuse to start new requests,
  70.         /// and avoid blocking.
  71.         /// </para>
  72.         /// </devdoc>
  73.         static internal bool IsThreadPoolLow()
  74.         {
  75.            
  76.             int workerThreads;
  77.             int completionPortThreads;
  78.             ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
  79.            
  80.             return workerThreads < 2 || completionPortThreads < 2;
  81.         }
  82.        
  83.         static internal bool HasShutdownStarted {
  84.             get { return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(); }
  85.         }
  86.        
  87.        
  88.         // ContextRelativeDemand
  89.         // Allows easily demanding a permission against a given ExecutionContext.
  90.         // Have requested the CLR to provide this method on ExecutionContext.
  91.         private static ContextCallback s_ContextRelativeDemandCallback;
  92.        
  93.         static internal ContextCallback ContextRelativeDemandCallback {
  94.             get {
  95.                 if (s_ContextRelativeDemandCallback == null)
  96.                     s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
  97.                 return s_ContextRelativeDemandCallback;
  98.             }
  99.         }
  100.        
  101.         private static void DemandCallback(object state)
  102.         {
  103.             ((CodeAccessPermission)state).Demand();
  104.         }
  105.        
  106.         // This is for checking if a hostname probably refers to this machine without going to DNS.
  107.         static internal bool GuessWhetherHostIsLoopback(string host)
  108.         {
  109.             string hostLower = host.ToLowerInvariant();
  110.             if (hostLower == "localhost" || hostLower == "loopback") {
  111.                 return true;
  112.             }
  113.            
  114.             return false;
  115.         }
  116.        
  117.         static internal bool IsFatal(Exception exception)
  118.         {
  119.             return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
  120.         }
  121.        
  122.         // Need a fast cached list of local addresses for internal use.
  123.         private static IPAddress[] _LocalAddresses;
  124.         private static object _LocalAddressesLock;
  125.        
  126.         private const int HostNameBufferLength = 256;
  127.         static internal string _LocalDomainName;
  128.        
  129.         // Copied from the old version of DNS.cs
  130.         // Returns a list of our local addresses by calling gethostbyname with null.
  131.         //
  132.         private static IPHostEntry GetLocalHost()
  133.         {
  134.             //
  135.             // IPv6 Changes: If IPv6 is enabled, we can't simply use the
  136.             // old IPv4 gethostbyname(null). Instead we need
  137.             // to do a more complete lookup.
  138.             //
  139.             if (Socket.SupportsIPv6) {
  140.                 //
  141.                 // IPv6 enabled: use getaddrinfo() of the local host name
  142.                 // to obtain this information. Need to get the machines
  143.                 // name as well - do that here so that we don't need to
  144.                 // Assert DNS permissions.
  145.                 //
  146.                 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
  147.                 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.gethostname(hostname, HostNameBufferLength);
  148.                
  149.                 if (errorCode != SocketError.Success) {
  150.                     throw new SocketException();
  151.                 }
  152.                
  153.                 return Dns.GetHostByName(hostname.ToString());
  154.             }
  155.             else {
  156.                 //
  157.                 // IPv6 disabled: use gethostbyname() to obtain information.
  158.                 //
  159.                 IntPtr nativePointer = UnsafeNclNativeMethods.OSSOCK.gethostbyname(null);
  160.                
  161.                 if (nativePointer == IntPtr.Zero) {
  162.                     throw new SocketException();
  163.                 }
  164.                
  165.                 return Dns.NativeToHostEntry(nativePointer);
  166.             }
  167.            
  168.         }
  169.         // GetLocalHost
  170.         static internal IPAddress[] LocalAddresses {
  171.             get {
  172.                 IPAddress[] local = _LocalAddresses;
  173.                 if (local != null) {
  174.                     return local;
  175.                 }
  176.                
  177.                 lock (LocalAddressesLock) {
  178.                     local = _LocalAddresses;
  179.                     if (local != null) {
  180.                         return local;
  181.                     }
  182.                    
  183.                     List<IPAddress> localList = new List<IPAddress>();
  184.                    
  185.                     try {
  186.                         IPHostEntry hostEntry = GetLocalHost();
  187.                         if (hostEntry != null) {
  188.                             if (hostEntry.HostName != null) {
  189.                                 int dot = hostEntry.HostName.IndexOf('.');
  190.                                 if (dot != -1) {
  191.                                     _LocalDomainName = hostEntry.HostName.Substring(dot);
  192.                                 }
  193.                             }
  194.                            
  195.                             IPAddress[] ipAddresses = hostEntry.AddressList;
  196.                             if (ipAddresses != null) {
  197.                                 foreach (IPAddress ipAddress in ipAddresses) {
  198.                                     localList.Add(ipAddress);
  199.                                 }
  200.                             }
  201.                         }
  202.                     }
  203.                     catch {
  204.                     }
  205.                    
  206.                     local = new IPAddress[localList.Count];
  207.                     int index = 0;
  208.                     foreach (IPAddress ipAddress in localList) {
  209.                         local[index] = ipAddress;
  210.                         index++;
  211.                     }
  212.                     _LocalAddresses = local;
  213.                    
  214.                     return local;
  215.                 }
  216.             }
  217.         }
  218.        
  219.         static internal bool IsAddressLocal(IPAddress ipAddress)
  220.         {
  221.             IPAddress[] localAddresses = NclUtilities.LocalAddresses;
  222.             for (int i = 0; i < localAddresses.Length; i++) {
  223.                 if (ipAddress.Equals(localAddresses[i], false)) {
  224.                     return true;
  225.                 }
  226.             }
  227.             return false;
  228.         }
  229.        
  230.         private static object LocalAddressesLock {
  231.             get {
  232.                 if (_LocalAddressesLock == null) {
  233.                     Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
  234.                 }
  235.                 return _LocalAddressesLock;
  236.             }
  237.         }
  238.     }
  239.    
  240.     static internal class NclConstants
  241.     {
  242.         static internal readonly object Sentinel = new object();
  243.         static internal readonly object[] EmptyObjectArray = new object[0];
  244.         static internal readonly Uri[] EmptyUriArray = new Uri[0];
  245.        
  246.         static internal readonly byte[] CRLF = new byte[] {(byte)'\r', (byte)'\n'};
  247.         static internal readonly byte[] ChunkTerminator = new byte[] {(byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n'};
  248.     }
  249.    
  250.     //
  251.     // A simple sync point, useful for deferring work. Just an int value with helper methods.
  252.     //
  253.     // The two events being synchronized are the "Triggering" event and the "Completing" event. The Triggering event
  254.     // marks the gate as being active; the first subsequent Completing event handles the action.
  255.     //
  256.     // First, a thread calls Trigger() to set the trigger on the gate. This means it needs some work to be done, but only
  257.     // after another operation (the Completing event) finishes. If Trigger() returns false, the Completing event already
  258.     // happened. When the Completing event occurs, that thread calls Complete(). It returns true if the gate has been
  259.     // previously triggered and the caller is the first one to complete it. The caller should then handle the pending work item.
  260.     //
  261.     // StartTrigger()/FinishTrigger() can be used instead of Trigger() if the triggering thread needs to set up some state
  262.     // (e.g. the pending work item). It will block Complete() in a spin-lock.
  263.     //
  264.     internal struct InterlockedGate
  265.     {
  266.         private int m_State;
  267.        
  268.         internal const int Open = 0;
  269.         // Initial state of gate.
  270.         internal const int Held = 1;
  271.         // Gate is being actively held by a thread - indeterminate state.
  272.         internal const int Triggered = 2;
  273.         // The triggering event has occurred.
  274.         internal const int Closed = 3;
  275.         // The gated event is done.
  276.         #if DEBUG
  277. /* Consider removing
  278.         internal int State
  279.         {
  280.             get
  281.             {
  282.                 return m_State;
  283.             }
  284.         }
  285.         */       
  286.         #endif
  287.        
  288.         // Only call when all threads are guaranteed to be done with the gate.
  289.         internal void Reset()
  290.         {
  291.             m_State = Open;
  292.         }
  293.        
  294.         // Returns false if the gate is already closed or triggered. If exclusive is true, throws if the gate is already
  295.         // triggered.
  296.         internal bool Trigger(bool exclusive)
  297.         {
  298.             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
  299.             if (exclusive && (gate == Held || gate == Triggered)) {
  300.                 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
  301.                 throw new InternalException();
  302.             }
  303.             return gate == Open;
  304.         }
  305.        
  306.         // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
  307.         // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
  308.         // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
  309.         // it in a finally.
  310.         //
  311.         // Returns false if the gate is already closed or triggered. If exclusive is true, throws if the gate is already
  312.         // triggered.
  313.         internal bool StartTrigger(bool exclusive)
  314.         {
  315.             int gate = Interlocked.CompareExchange(ref m_State, Held, Open);
  316.             if (exclusive && (gate == Held || gate == Triggered)) {
  317.                 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already triggered.");
  318.                 throw new InternalException();
  319.             }
  320.             return gate == Open;
  321.         }
  322.        
  323.         // Gate must be held by StartTrigger().
  324.         internal void FinishTrigger()
  325.         {
  326.             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Held);
  327.             if (gate != Held) {
  328.                 GlobalLog.Assert("InterlockedGate::FinishTrigger", "Gate not held.");
  329.                 throw new InternalException();
  330.             }
  331.         }
  332.        
  333.         // Returns false if the gate had never been triggered or is already closed.
  334.         internal bool Complete()
  335.         {
  336.             int gate;
  337.            
  338.             // Spin while the gate is being held, allowing the other thread to set invariants up.
  339.             while ((gate = Interlocked.CompareExchange(ref m_State, Closed, Triggered)) != Triggered) {
  340.                 if (gate == Closed) {
  341.                     return false;
  342.                 }
  343.                
  344.                 if (gate == Open) {
  345.                     if (Interlocked.CompareExchange(ref m_State, Closed, Open) == Open) {
  346.                         return false;
  347.                     }
  348.                    
  349.                     continue;
  350.                 }
  351.                
  352.                 // gate == Held
  353.                 Thread.SpinWait(1);
  354.             }
  355.            
  356.             return true;
  357.         }
  358.     }
  359.    
  360.    
  361.    
  362.    
  363.    
  364.    
  365.     //
  366.     // support class for Validation related stuff.
  367.     //
  368.     static internal class ValidationHelper
  369.     {
  370.        
  371.         public static string[] EmptyArray = new string[0];
  372.        
  373.         static internal readonly char[] InvalidMethodChars = new char[] {' ', '\r', '\n', '\t'};
  374.        
  375.         // invalid characters that cannot be found in a valid method-verb or http header
  376.         static internal readonly char[] InvalidParamChars = new char[] {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"',
  377.         '\'', '/', '[', ']', '?', '=', '{', '}', ' ', '\t',
  378.         '\r', '\n'};
  379.        
  380.         public static string[] MakeEmptyArrayNull(string[] stringArray)
  381.         {
  382.             if (stringArray == null || stringArray.Length == 0) {
  383.                 return null;
  384.             }
  385.             else {
  386.                 return stringArray;
  387.             }
  388.         }
  389.        
  390.         public static string MakeStringNull(string stringValue)
  391.         {
  392.             if (stringValue == null || stringValue.Length == 0) {
  393.                 return null;
  394.             }
  395.             else {
  396.                 return stringValue;
  397.             }
  398.         }
  399.        
  400. /*
  401.         //                                   
  402.         public static string MakeStringEmpty(string stringValue) {
  403.             if ( stringValue == null || stringValue.Length == 0) {
  404.                 return String.Empty;
  405.             } else {
  406.                 return stringValue;
  407.             }
  408.         }
  409.         */       
  410.        
  411.        
  412.         public static string ExceptionMessage(Exception exception)
  413.         {
  414.             if (exception == null) {
  415.                 return string.Empty;
  416.             }
  417.             if (exception.InnerException == null) {
  418.                 return exception.Message;
  419.             }
  420.             return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
  421.         }
  422.        
  423.         public static string ToString(object objectValue)
  424.         {
  425.             if (objectValue == null) {
  426.                 return "(null)";
  427.             }
  428.             else if (objectValue is string && ((string)objectValue).Length == 0) {
  429.                 return "(string.empty)";
  430.             }
  431.             else if (objectValue is Exception) {
  432.                 return ExceptionMessage(objectValue as Exception);
  433.             }
  434.             else if (objectValue is IntPtr) {
  435.                 return "0x" + ((IntPtr)objectValue).ToString("x");
  436.             }
  437.             else {
  438.                 return objectValue.ToString();
  439.             }
  440.         }
  441.         public static string HashString(object objectValue)
  442.         {
  443.             if (objectValue == null) {
  444.                 return "(null)";
  445.             }
  446.             else if (objectValue is string && ((string)objectValue).Length == 0) {
  447.                 return "(string.empty)";
  448.             }
  449.             else {
  450.                 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
  451.             }
  452.         }
  453.        
  454.         public static bool IsInvalidHttpString(string stringValue)
  455.         {
  456.             return stringValue.IndexOfAny(InvalidParamChars) != -1;
  457.         }
  458.        
  459.         public static bool IsBlankString(string stringValue)
  460.         {
  461.             return stringValue == null || stringValue.Length == 0;
  462.         }
  463.        
  464. /*
  465.         //                                   
  466.         public static bool ValidateUInt32(long address) {
  467.             // on false, API should throw new ArgumentOutOfRangeException("address");
  468.             return address>=0x00000000 && address<=0xFFFFFFFF;
  469.         }
  470.         */       
  471.        
  472.         public static bool ValidateTcpPort(int port)
  473.         {
  474.             // on false, API should throw new ArgumentOutOfRangeException("port");
  475.             return port >= IPEndPoint.MinPort && port <= IPEndPoint.MaxPort;
  476.         }
  477.        
  478.         public static bool ValidateRange(int actual, int fromAllowed, int toAllowed)
  479.         {
  480.             // on false, API should throw new ArgumentOutOfRangeException("argument");
  481.             return actual >= fromAllowed && actual <= toAllowed;
  482.         }
  483.        
  484.         /*
  485.         //                                   
  486.         public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
  487.             // on false, API should throw new ArgumentOutOfRangeException("argument");
  488.             return actual>=fromAllowed && actual<=toAllowed;
  489.         }
  490.         */       
  491.     }
  492.    
  493.     static internal class ExceptionHelper
  494.     {
  495.         static internal readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
  496.         static internal readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
  497.         static internal readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
  498.         static internal readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
  499.         static internal readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
  500.         static internal readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
  501.        
  502.         static internal NotImplementedException MethodNotImplementedException {
  503.             get { return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException)); }
  504.         }
  505.        
  506.         static internal NotImplementedException PropertyNotImplementedException {
  507.             get { return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException)); }
  508.         }
  509.        
  510.         static internal NotSupportedException MethodNotSupportedException {
  511.             get { return new NotSup