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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ServicePointManager.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.Collections;
  18.     using System.Collections.Generic;
  19.     using System.Configuration;
  20.     using System.Net.Configuration;
  21.     using System.Net.Sockets;
  22.     using System.Net.Security;
  23.     using System.Security.Permissions;
  24.     using System.Security.Cryptography.X509Certificates;
  25.     using System.Threading;
  26.     using System.Globalization;
  27.    
  28.    
  29.     // This turned to be a legacy type name that is simply forwarded to System.Security.Authentication.SslProtocols defined values.
  30.    
  31.     //
  32.     // The ServicePointManager class hands out ServicePoints (may exist or be created
  33.     // as needed) and makes sure they are garbage collected when they expire.
  34.     // The ServicePointManager runs in its own thread so that it never
  35.     //
  36.    
  37.     /// <devdoc>
  38.     /// <para>Manages the collection of <see cref='System.Net.ServicePoint'/> instances.</para>
  39.     /// </devdoc>
  40.     ///
  41.     public class ServicePointManager
  42.     {
  43.        
  44.         /// <devdoc>
  45.         /// <para>
  46.         /// The number of non-persistant connections allowed on a <see cref='System.Net.ServicePoint'/>.
  47.         /// </para>
  48.         /// </devdoc>
  49.         public const int DefaultNonPersistentConnectionLimit = 4;
  50.         /// <devdoc>
  51.         /// <para>
  52.         /// The default number of persistent connections allowed on a <see cref='System.Net.ServicePoint'/>.
  53.         /// </para>
  54.         /// </devdoc>
  55.         public const int DefaultPersistentConnectionLimit = 2;
  56.        
  57.         /// <devdoc>
  58.         /// <para>
  59.         /// The default number of persistent connections when runninger under ASP+.
  60.         /// </para>
  61.         /// </devdoc>
  62.         private const int DefaultAspPersistentConnectionLimit = 10;
  63.        
  64.        
  65.         static internal readonly string SpecialConnectGroupName = "/.NET/NetClasses/HttpWebRequest/CONNECT__Group$$/";
  66.         static internal readonly TimerThread.Callback s_IdleServicePointTimeoutDelegate = new TimerThread.Callback(IdleServicePointTimeoutCallback);
  67.        
  68.        
  69.         //
  70.         // data - only statics used
  71.         //
  72.        
  73.         //
  74.         // s_ServicePointTable - Uri of ServicePoint is the hash key
  75.         // We provide our own comparer function that knows about Uris
  76.         //
  77.        
  78.         //also used as a lock object
  79.         private static Hashtable s_ServicePointTable = new Hashtable(10);
  80.        
  81.         // IIS6 has 120 sec for an idle connection timeout, we should have a little bit less.
  82.         private static TimerThread.Queue s_ServicePointIdlingQueue = TimerThread.GetOrCreateQueue(100 * 1000);
  83.         private static int s_MaxServicePoints = 0;
  84.         private static Hashtable s_ConfigTable = null;
  85.         private static int s_ConnectionLimit = PersistentConnectionLimit;
  86.        
  87.        
  88.         //
  89.         // InternalConnectionLimit -
  90.         // set/get Connection Limit on demand, checking config beforehand
  91.         //
  92.        
  93.         private static bool s_UserChangedLimit;
  94.         private static int InternalConnectionLimit {
  95.             get {
  96.                 if (s_ConfigTable == null) {
  97.                     // init config
  98.                     s_ConfigTable = ConfigTable;
  99.                 }
  100.                 return s_ConnectionLimit;
  101.             }
  102.             set {
  103.                 if (s_ConfigTable == null) {
  104.                     // init config
  105.                     s_ConfigTable = ConfigTable;
  106.                 }
  107.                 s_UserChangedLimit = true;
  108.                 s_ConnectionLimit = value;
  109.             }
  110.         }
  111.        
  112.         //
  113.         // PersistentConnectionLimit -
  114.         // Determines the correct connection limit based on whether with running with ASP+
  115.         // The following order is followed generally for figuring what ConnectionLimit size to use
  116.         // 1. If ServicePoint.ConnectionLimit is set, then take that value
  117.         // 2. If ServicePoint has a specific config setting, then take that value
  118.         // 3. If ServicePoint.DefaultConnectionLimit is set, then take that value
  119.         // 4. If ServicePoint is localhost, then set to infinite (TO Should we change this value?)
  120.         // 5. If ServicePointManager has a default config connection limit setting, then take that value
  121.         // 6. If ServicePoint is running under ASP+, then set value to 10, else set it to 2
  122.         //
  123.         private static int PersistentConnectionLimit {
  124.             get {
  125.                 {
  126.                     return DefaultPersistentConnectionLimit;
  127.                 }
  128.             }
  129.         }
  130.        
  131. /* Consider Removing
  132.         //
  133.         // InternalServicePointCount -
  134.         //  Gets the active number of ServicePoints being used
  135.         //
  136.         internal static int InternalServicePointCount {
  137.             get {
  138.                 return s_ServicePointTable.Count;
  139.             }
  140.         }
  141.         */       
  142.        
  143.         [System.Diagnostics.Conditional("DEBUG")]
  144.         static internal void Debug(int requestHash)
  145.         {
  146.             try {
  147.                 foreach (WeakReference servicePointReference in s_ServicePointTable) {
  148.                     ServicePoint servicePoint;
  149.                     if (servicePointReference != null && servicePointReference.IsAlive) {
  150.                         servicePoint = (ServicePoint)servicePointReference.Target;
  151.                     }
  152.                     else {
  153.                         servicePoint = null;
  154.                     }
  155.                     if (servicePoint != null) {
  156.                         servicePoint.Debug(requestHash);
  157.                     }
  158.                 }
  159.             }
  160.             catch (Exception e) {
  161.                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
  162.                     throw;
  163.                 }
  164.             }
  165.             catch {
  166.             }
  167.         }
  168.        
  169.         //
  170.         // ConfigTable -
  171.         // read ConfigTable from Config, or create
  172.         // a default on failure
  173.         //
  174.        
  175.         private static Hashtable ConfigTable {
  176.             get {
  177.                 if (s_ConfigTable == null) {
  178.                     lock (s_ServicePointTable) {
  179.                         if (s_ConfigTable == null) {
  180.                             Hashtable configTable;
  181.                             configTable = (Hashtable)ConnectionManagementSectionInternal.GetSection().ConnectionManagement;
  182.                            
  183.                             if (configTable == null) {
  184.                                 configTable = new Hashtable();
  185.                             }
  186.                            
  187.                             // we piggy back loading the ConnectionLimit here
  188.                             if (configTable.ContainsKey("*")) {
  189.                                 int connectionLimit = (int)configTable["*"];
  190.                                 if (connectionLimit < 1) {
  191.                                     connectionLimit = PersistentConnectionLimit;
  192.                                 }
  193.                                 s_ConnectionLimit = connectionLimit;
  194.                             }
  195.                             s_ConfigTable = configTable;
  196.                         }
  197.                     }
  198.                 }
  199.                 return s_ConfigTable;
  200.             }
  201.         }
  202.        
  203.        
  204.         static internal TimerThread.Callback IdleServicePointTimeoutDelegate {
  205.             get { return s_IdleServicePointTimeoutDelegate; }
  206.         }
  207.        
  208.         private static void IdleServicePointTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
  209.         {
  210.             ServicePoint servicePoint = (ServicePoint)context;
  211.            
  212.             lock (s_ServicePointTable) {
  213.                 s_ServicePointTable.Remove(servicePoint.LookupString);
  214.             }
  215.            
  216.             servicePoint.ReleaseAllConnectionGroups();
  217.         }
  218.        
  219.        
  220.         //
  221.         // constructors
  222.         //
  223.        
  224.         private ServicePointManager()
  225.         {
  226.         }
  227.        
  228.        
  229.         //
  230.         // accessors
  231.         //
  232.        
  233.         /// <devdoc>
  234.         /// <para>Gets or sets the maximum number of <see cref='System.Net.ServicePoint'/> instances that should be maintained at any
  235.         /// time.</para>
  236.         /// </devdoc>
  237.         public static int MaxServicePoints {
  238.             get { return s_MaxServicePoints; }
  239.             set {
  240.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  241.                 if (!ValidationHelper.ValidateRange(value, 0, Int32.MaxValue)) {
  242.                     throw new ArgumentOutOfRangeException("value");
  243.                 }
  244.                 s_MaxServicePoints = value;
  245.             }
  246.         }
  247.        
  248.         /// <devdoc>
  249.         /// <para>[To be supplied.]</para>
  250.         /// </devdoc>
  251.         public static int DefaultConnectionLimit {
  252.             get { return InternalConnectionLimit; }
  253.             set {
  254.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  255.                 if (value > 0) {
  256.                     InternalConnectionLimit = value;
  257.                    
  258.                 }
  259.                 else {
  260.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall));
  261.                 }
  262.             }
  263.         }
  264.        
  265.        
  266.        
  267.         /// <devdoc>
  268.         /// <para>Gets or sets the maximum idle time in seconds of a <see cref='System.Net.ServicePoint'/>.</para>
  269.         /// </devdoc>
  270.         public static int MaxServicePointIdleTime {
  271.             get { return s_ServicePointIdlingQueue.Duration; }
  272.             set {
  273.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  274.                 if (!ValidationHelper.ValidateRange(value, Timeout.Infinite, Int32.MaxValue)) {
  275.                     throw new ArgumentOutOfRangeException("value");
  276.                 }
  277.                 if (s_ServicePointIdlingQueue.Duration != value) {
  278.                     s_ServicePointIdlingQueue = TimerThread.GetOrCreateQueue(value);
  279.                 }
  280.             }
  281.         }
  282.        
  283.         /// <devdoc>
  284.         /// <para>
  285.         /// Gets or sets indication whether use of the Nagling algorithm is desired.
  286.         /// Changing this value does not affect existing <see cref='System.Net.ServicePoint'/> instances but only to new ones that are created from that moment on.
  287.         /// </para>
  288.         /// </devdoc>
  289.         public static bool UseNagleAlgorithm {
  290.             get { return SettingsSectionInternal.Section.UseNagleAlgorithm; }
  291.             set { SettingsSectionInternal.Section.UseNagleAlgorithm = value; }
  292.         }
  293.        
  294.         /// <devdoc>
  295.         /// <para>
  296.         /// Gets or sets indication whether 100-continue behaviour is desired.
  297.         /// Changing this value does not affect existing <see cref='System.Net.ServicePoint'/> instances but only to new ones that are created from that moment on.
  298.         /// </para>
  299.         /// </devdoc>
  300.         public static bool Expect100Continue {
  301.             get { return SettingsSectionInternal.Section.Expect100Continue; }
  302.             set { SettingsSectionInternal.Section.Expect100Continue = value; }
  303.         }
  304.        
  305.         /// <devdoc>
  306.         /// <para>
  307.         /// Enables the use of DNS round robin access, meaning a different IP
  308.         /// address may be used on each connection, when more than one IP is availble
  309.         /// </para>
  310.         /// </devdoc>
  311.         public static bool EnableDnsRoundRobin {
  312.             get { return SettingsSectionInternal.Section.EnableDnsRoundRobin; }
  313.             set { SettingsSectionInternal.Section.EnableDnsRoundRobin = value; }
  314.         }
  315.        
  316.         /// <devdoc>
  317.         /// <para>
  318.         /// Causes us to go back and reresolve addresses through DNS, even when
  319.         /// there were no recorded failures. -1 is infinite. Time should be in ms
  320.         /// </para>
  321.         /// </devdoc>
  322.         public static int DnsRefreshTimeout {
  323.             get { return SettingsSectionInternal.Section.DnsRefreshTimeout; }
  324.             set {
  325.                 if (value < -1) {
  326.                     SettingsSectionInternal.Section.DnsRefreshTimeout = -1;
  327.                 }
  328.                 else {
  329.                     SettingsSectionInternal.Section.DnsRefreshTimeout = value;
  330.                 }
  331.             }
  332.         }
  333.        
  334.        
  335.         public static bool CheckCertificateRevocationList {
  336.             get { return SettingsSectionInternal.Section.CheckCertificateRevocationList; }
  337.             set {
  338.                 //Prevent an applet to override default certificate checking
  339.                 ExceptionHelper.UnmanagedPermission.Demand();
  340.                 SettingsSectionInternal.Section.CheckCertificateRevocationList = value;
  341.             }
  342.         }
  343.        
  344.         static internal bool CheckCertificateName {
  345.             get { return SettingsSectionInternal.Section.CheckCertificateName; }
  346.         }
  347.        
  348.         //
  349.         // class methods
  350.         //
  351.        
  352.         //
  353.         // MakeQueryString - Just a short macro to handle creating the query
  354.         // string that we search for host ports in the host list
  355.         //
  356.         static internal string MakeQueryString(Uri address)
  357.         {
  358.             if (address.IsDefaultPort)
  359.                 return address.Scheme + "://" + address.DnsSafeHost;
  360.             else
  361.                 return address.Scheme + "://" + address.DnsSafeHost + ":" + address.Port.ToString();
  362.         }
  363.        
  364.         static internal string MakeQueryString(Uri address1, bool isProxy)
  365.         {
  366.             if (isProxy) {
  367.                 return MakeQueryString(address1) + "://proxy";
  368.             }
  369.             else {
  370.                 return MakeQueryString(address1);
  371.             }
  372.         }
  373.        
  374.         //
  375.         // FindServicePoint - Query using an Uri string for a given ServerPoint Object
  376.         //
  377.        
  378.         /// <devdoc>
  379.         /// <para>Finds an existing <see cref='System.Net.ServicePoint'/> or creates a new <see cref='System.Net.ServicePoint'/> to manage communications to the
  380.         /// specified Uniform Resource Identifier.</para>
  381.         /// </devdoc>
  382.         public static ServicePoint FindServicePoint(Uri address)
  383.         {
  384.             return FindServicePoint(address, null);
  385.         }
  386.        
  387.        
  388.         /// <devdoc>
  389.         /// <para>Finds an existing <see cref='System.Net.ServicePoint'/> or creates a new <see cref='System.Net.ServicePoint'/> to manage communications to the
  390.         /// specified Uniform Resource Identifier.</para>
  391.         /// </devdoc>
  392.         public static ServicePoint FindServicePoint(string uriString, IWebProxy proxy)
  393.         {
  394.             Uri uri = new Uri(uriString);
  395.             return FindServicePoint(uri, proxy);
  396.         }
  397.        
  398.        
  399.         //
  400.         // FindServicePoint - Query using an Uri for a given server point
  401.         //
  402.        
  403.         /// <devdoc>
  404.         /// <para>Findes an existing <see cref='System.Net.ServicePoint'/> or creates a new <see cref='System.Net.ServicePoint'/> to manage communications to the specified <see cref='System.Uri'/>
  405.         /// instance.</para>
  406.         /// </devdoc>
  407.         public static ServicePoint FindServicePoint(Uri address, IWebProxy proxy)
  408.         {
  409.             ProxyChain chain;
  410.             HttpAbortDelegate abortDelegate = null;
  411.             int abortState = 0;
  412.             return FindServicePoint(address, proxy, out chain, ref abortDelegate, ref abortState);
  413.         }
  414.        
  415.         // If abortState becomes non-zero, the attempt to find a service point has been aborted.
  416.         static internal ServicePoint FindServicePoint(Uri address, IWebProxy proxy, out ProxyChain chain, ref HttpAbortDelegate abortDelegate, ref int abortState)
  417.         {
  418.             if (address == null) {
  419.                 throw new ArgumentNullException("address");
  420.             }
  421.             GlobalLog.Enter("ServicePointManager::FindServicePoint() address:" + address.ToString());
  422.            
  423.             bool isProxyServicePoint = false;
  424.             chain = null;
  425.            
  426.             //
  427.             // find proxy info, and then switch on proxy
  428.             //
  429.             Uri proxyAddress = null;
  430.             if (proxy != null && !address.IsLoopback) {
  431.                 IAutoWebProxy autoProxy = proxy as IAutoWebProxy;
  432.                 if (autoProxy != null) {
  433.                     chain = autoProxy.GetProxies(address);
  434.                    
  435.                     // Set up our ability to abort this MoveNext call. Note that the current implementations of ProxyChain will only
  436.                     // take time on the first call, so this is the only place we do this. If a new ProxyChain takes time in later
  437.                     // calls, this logic should be copied to other places MoveNext is called.
  438.                     GlobalLog.Assert(abortDelegate == null, "ServicePointManager::FindServicePoint()|AbortDelegate already set.");
  439.                     abortDelegate = chain.HttpAbortDelegate;
  440.                     try {
  441.                         Thread.MemoryBarrier();
  442.                         if (abortState != 0) {
  443.                             Exception exception = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
  444.                             GlobalLog.LeaveException("ServicePointManager::FindServicePoint() Request aborted before proxy lookup.", exception);
  445.                             throw exception;
  446.                         }
  447.                        
  448.                         if (!chain.Enumerator.MoveNext()) {
  449.                             GlobalLog.Assert("ServicePointManager::FindServicePoint()|GetProxies() returned zero proxies.");
  450.                             /*
  451.                             Exception exception = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.RequestProhibitedByProxy), WebExceptionStatus.RequestProhibitedByProxy);
  452.                             GlobalLog.LeaveException("ServicePointManager::FindServicePoint() Proxy prevented request.", exception);
  453.                             throw exception;
  454. */                           
  455.                         }
  456.                         proxyAddress = chain.Enumerator.Current;
  457.                     }
  458.                     finally {
  459.                         abortDelegate = null;
  460.                     }
  461.                 }
  462.                 else if (!proxy.IsBypassed(address)) {
  463.                     // use proxy support
  464.                     // rework address
  465.                     proxyAddress = proxy.GetProxy(address);
  466.                 }
  467.                
  468.                 // null means DIRECT
  469.                 if (proxyAddress != null) {
  470.                     address = proxyAddress;
  471.                     isProxyServicePoint = true;
  472.                 }
  473.             }
  474.            
  475.             ServicePoint servicePoint = FindServicePointHelper(address, isProxyServicePoint);
  476.             GlobalLog.Leave("ServicePointManager::FindServicePoint() servicePoint#" + ValidationHelper.HashString(servicePoint));
  477.             return servicePoint;
  478.         }
  479.        
  480.         // Returns null if we get to the end of the chain.
  481.         static internal ServicePoint FindServicePoint(ProxyChain chain)
  482.         {
  483.             GlobalLog.Print("ServicePointManager::FindServicePoint() Calling chained version.");
  484.             if (!chain.Enumerator.MoveNext()) {
  485.                 return null;
  486.             }
  487.            
  488.             Uri proxyAddress = chain.Enumerator.Current;
  489.             return FindServicePointHelper(proxyAddress == null ? chain.Destination : proxyAddress, proxyAddress != null);
  490.         }
  491.        
  492.         private static ServicePoint FindServicePointHelper(Uri address, bool isProxyServicePoint)
  493.         {
  494.             GlobalLog.Enter("ServicePointManager::FindServicePointHelper() address:" + address.ToString());
  495.            
  496.             if (isProxyServicePoint) {
  497.                 if (address.Scheme != Uri.UriSchemeHttp) {
  498.                     Exception exception = new NotSupportedException(SR.GetString(SR.net_proxyschemenotsupported, address.Scheme));
  499.                     GlobalLog.LeaveException("ServicePointManager::FindServicePointHelper() proxy has unsupported scheme:" + address.Scheme.ToString(), exception);
  500.                     throw exception;
  501.                 }
  502.             }
  503.            
  504.             //
  505.             // Search for the correct proxy host,
  506.             // then match its acutal host by using ConnectionGroups
  507.             // which are located on the actual ServicePoint.
  508.             //
  509.             string tempEntry = MakeQueryString(address, isProxyServicePoint);
  510.            
  511.             // lookup service point in the table
  512.             ServicePoint servicePoint = null;
  513.             GlobalLog.Print("ServicePointManager::FindServicePointHelper() locking and looking up tempEntry:[" + tempEntry.ToString() + "]");
  514.             lock (s_ServicePointTable) {
  515.                 // once we grab the lock, check if it wasn't already added
  516.                 WeakReference servicePointReference = s_ServicePointTable[tempEntry] as WeakReference;
  517.                 GlobalLog.Print("ServicePointManager::FindServicePointHelper() lookup returned WeakReference#" + ValidationHelper.HashString(servicePointReference));
  518.                 if (servicePointReference != null) {
  519.                     servicePoint = (ServicePoint)servicePointReference.Target;
  520.                     GlobalLog.Print("ServicePointManager::FindServicePointHelper() successful lookup returned ServicePoint#" + ValidationHelper.HashString(servicePoint));
  521.                 }
  522.                 if (servicePoint == null) {
  523.                     // lookup failure or timeout, we need to create a new ServicePoint
  524.                     if (s_MaxServicePoints <= 0 || s_ServicePointTable.Count < s_MaxServicePoints) {
  525.                         // Determine Connection Limit
  526.                         int connectionLimit = InternalConnectionLimit;
  527.                         string schemeHostPort = MakeQueryString(address);
  528.                         bool userDefined = s_UserChangedLimit;
  529.                         if (ConfigTable.ContainsKey(schemeHostPort)) {
  530.                             connectionLimit = (int)ConfigTable[schemeHostPort];
  531.                             userDefined = true;
  532.                         }
  533.                         servicePoint = new ServicePoint(address, s_ServicePointIdlingQueue, connectionLimit, tempEntry, userDefined, isProxyServicePoint);
  534.                         GlobalLog.Print("ServicePointManager::FindServicePointHelper() created ServicePoint#" + ValidationHelper.HashString(servicePoint));
  535.                         servicePointReference = new WeakReference(servicePoint);
  536.                         s_ServicePointTable[tempEntry] = servicePointReference;
  537.                         GlobalLog.Print("ServicePointManager::FindServicePointHelper() adding entry WeakReference#" + ValidationHelper.HashString(servicePointReference) + " key:[" + tempEntry + "]");
  538.                     }
  539.                     else {
  540.                         Exception exception = new InvalidOperationException(SR.GetString(SR.net_maxsrvpoints));
  541.                         GlobalLog.LeaveException("ServicePointManager::FindServicePointHelper() reached the limit count:" + s_ServicePointTable.Count.ToString() + " limit:" + s_MaxServicePoints.ToString(), exception);
  542.                         throw exception;
  543.                     }
  544.                 }
  545.             }
  546.            
  547.             GlobalLog.Leave("ServicePointManager::FindServicePointHelper() servicePoint#" + ValidationHelper.HashString(servicePoint));
  548.             return servicePoint;
  549.         }
  550.        
  551.         //
  552.         // FindServicePoint - Query using an Uri for a given server point
  553.         //
  554.        
  555.         /// <devdoc>
  556.         /// <para>Findes an existing <see cref='System.Net.ServicePoint'/> or creates a new <see cref='System.Net.ServicePoint'/> to manage communications to the specified <see cref='System.Uri'/>
  557.         /// instance.</para>
  558.         /// </devdoc>
  559.         static internal ServicePoint FindServicePoint(string host, int port)
  560.         {
  561.             if (host == null) {
  562.                 throw new ArgumentNullException("address");
  563.             }
  564.             GlobalLog.Enter("ServicePointManager::FindServicePoint() host:" + host.ToString());
  565.            
  566.             string tempEntry = null;
  567.             bool isProxyServicePoint = false;
  568.            
  569.            
  570.             //
  571.             // Search for the correct proxy host,
  572.             // then match its acutal host by using ConnectionGroups
  573.             // which are located on the actual ServicePoint.
  574.             //
  575.             tempEntry = "ByHost:" + host + ":" + port.ToString(CultureInfo.InvariantCulture);
  576.             // lookup service point in the table
  577.             ServicePoint servicePoint = null;
  578.             GlobalLog.Print("ServicePointManager::FindServicePoint() locking and looking up tempEntry:[" + tempEntry.ToString() + "]");
  579.             lock (s_ServicePointTable) {
  580.                 // once we grab the lock, check if it wasn't already added
  581.                 WeakReference servicePointReference = s_ServicePointTable[tempEntry] as WeakReference;
  582.                 GlobalLog.Print("ServicePointManager::FindServicePoint() lookup returned WeakReference#" + ValidationHelper.HashString(servicePointReference));
  583.                 if (servicePointReference != null) {
  584.                     servicePoint = (ServicePoint)servicePointReference.Target;
  585.                     GlobalLog.Print("ServicePointManager::FindServicePoint() successfull lookup returned ServicePoint#" + ValidationHelper.HashString(servicePoint));
  586.                 }
  587.                 if (servicePoint == null) {
  588.                     // lookup failure or timeout, we need to create a new ServicePoint
  589.                     if (s_MaxServicePoints <= 0 || s_ServicePointTable.Count < s_MaxServicePoints) {
  590.                         // Determine Connection Limit
  591.                         int connectionLimit = InternalConnectionLimit;
  592.                         bool userDefined = s_UserChangedLimit;
  593.                         string schemeHostPort = host + ":" + port.ToString(CultureInfo.InvariantCulture);
  594.                        
  595.                         if (ConfigTable.ContainsKey(schemeHostPort)) {
  596.                             connectionLimit = (int)ConfigTable[schemeHostPort];
  597.                             userDefined = true;
  598.                         }
  599.                         servicePoint = new ServicePoint(host, port, s_ServicePointIdlingQueue, connectionLimit, tempEntry, userDefined, isProxyServicePoint);
  600.                         GlobalLog.Print("ServicePointManager::FindServicePoint() created ServicePoint#" + ValidationHelper.HashString(servicePoint));
  601.                         servicePointReference = new WeakReference(servicePoint);
  602.                         s_ServicePointTable[tempEntry] = servicePointReference;
  603.                         GlobalLog.Print("ServicePointManager::FindServicePoint() adding entry WeakReference#" + ValidationHelper.HashString(servicePointReference) + " key:[" + tempEntry + "]");
  604.                     }
  605.                     else {
  606.                         Exception exception = new InvalidOperationException(SR.GetString(SR.net_maxsrvpoints));
  607.                         GlobalLog.LeaveException("ServicePointManager::FindServicePoint() reached the limit count:" + s_ServicePointTable.Count.ToString() + " limit:" + s_MaxServicePoints.ToString(), exception);
  608.                         throw exception;
  609.                     }
  610.                 }
  611.             }
  612.            
  613.             GlobalLog.Leave("ServicePointManager::FindServicePoint() servicePoint#" + ValidationHelper.HashString(servicePoint));
  614.             return servicePoint;
  615.         }
  616.     }
  617. }

Developer Fusion