ServicePointManager.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // System.Net.ServicePointManager
  3. //
  4. // Author:
  5. // Lawrence Pit ([email protected])
  6. //
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Specialized;
  10. using System.Configuration;
  11. using System.Net.Configuration;
  12. using System.Security.Cryptography.X509Certificates;
  13. //
  14. // notes:
  15. // A service point manager manages service points (duh!).
  16. // A service point maintains a list of connections (per scheme + authority).
  17. // According to HttpWebRequest.ConnectionGroupName each connection group
  18. // creates additional connections. therefor, a service point has a hashtable
  19. // of connection groups where each value is a list of connections.
  20. //
  21. // when we need to make an HttpWebRequest, we need to do the following:
  22. // 1. find service point, given Uri and Proxy
  23. // 2. find connection group, given service point and group name
  24. // 3. find free connection in connection group, or create one (if ok due to limits)
  25. // 4. lease connection
  26. // 5. execute request
  27. // 6. when finished, return connection
  28. //
  29. namespace System.Net
  30. {
  31. class DummyPolicy : ICertificatePolicy
  32. {
  33. public bool CheckValidationResult (ServicePoint point,
  34. X509Certificate certificate,
  35. WebRequest request,
  36. int certificateProblem)
  37. {
  38. return (certificateProblem == 0);
  39. }
  40. }
  41. public class ServicePointManager
  42. {
  43. private static HybridDictionary servicePoints = new HybridDictionary ();
  44. // Static properties
  45. private static ICertificatePolicy policy = new DummyPolicy ();
  46. private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
  47. private static int maxServicePointIdleTime = 900000; // 15 minutes
  48. private static int maxServicePoints = 0;
  49. // Fields
  50. public const int DefaultNonPersistentConnectionLimit = 4;
  51. public const int DefaultPersistentConnectionLimit = 2;
  52. const string configKey = "system.net/connectionManagement";
  53. static Hashtable config;
  54. static ServicePointManager ()
  55. {
  56. ConnectionManagementData manager;
  57. manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
  58. config = manager.Data;
  59. }
  60. // Constructors
  61. private ServicePointManager ()
  62. {
  63. }
  64. // Properties
  65. public static ICertificatePolicy CertificatePolicy {
  66. get { return policy; }
  67. set { policy = value; }
  68. }
  69. public static int DefaultConnectionLimit {
  70. get { return defaultConnectionLimit; }
  71. set {
  72. if (value <= 0)
  73. throw new ArgumentOutOfRangeException ("value");
  74. defaultConnectionLimit = value;
  75. }
  76. }
  77. public static int MaxServicePointIdleTime {
  78. get {
  79. return maxServicePointIdleTime;
  80. }
  81. set {
  82. if (value < -2 || value > Int32.MaxValue)
  83. throw new ArgumentOutOfRangeException ("value");
  84. maxServicePointIdleTime = value;
  85. }
  86. }
  87. public static int MaxServicePoints {
  88. get {
  89. return maxServicePoints;
  90. }
  91. set {
  92. if (value < 0)
  93. throw new ArgumentException ("value");
  94. maxServicePoints = value;
  95. RecycleServicePoints ();
  96. }
  97. }
  98. // Methods
  99. public static ServicePoint FindServicePoint (Uri address)
  100. {
  101. return FindServicePoint (address, GlobalProxySelection.Select);
  102. }
  103. public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
  104. {
  105. return FindServicePoint (new Uri(uriString), proxy);
  106. }
  107. public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
  108. {
  109. if (address == null)
  110. throw new ArgumentNullException ("address");
  111. RecycleServicePoints ();
  112. bool usesProxy = false;
  113. if (proxy != null && !proxy.IsBypassed(address)) {
  114. usesProxy = true;
  115. address = proxy.GetProxy (address);
  116. if (address.Scheme != "http" && address.Scheme != "https")
  117. throw new NotSupportedException ("Proxy scheme not supported.");
  118. }
  119. address = new Uri (address.Scheme + "://" + address.Authority);
  120. ServicePoint sp = null;
  121. lock (servicePoints) {
  122. sp = servicePoints [address] as ServicePoint;
  123. if (sp != null)
  124. return sp;
  125. if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
  126. throw new InvalidOperationException ("maximum number of service points reached");
  127. string addr = address.ToString ();
  128. int limit = defaultConnectionLimit;
  129. if (config.Contains (addr))
  130. limit = (int) config [addr];
  131. sp = new ServicePoint (address, limit, maxServicePointIdleTime);
  132. sp.UsesProxy = usesProxy;
  133. servicePoints.Add (address, sp);
  134. }
  135. return sp;
  136. }
  137. // Internal Methods
  138. internal static void RecycleServicePoints ()
  139. {
  140. ArrayList toRemove = new ArrayList ();
  141. lock (servicePoints) {
  142. IDictionaryEnumerator e = servicePoints.GetEnumerator ();
  143. while (e.MoveNext ()) {
  144. ServicePoint sp = (ServicePoint) e.Value;
  145. if (sp.AvailableForRecycling) {
  146. toRemove.Add (e.Key);
  147. Console.WriteLine ("Reciclo: {0}", e.Key);
  148. }
  149. }
  150. for (int i = 0; i < toRemove.Count; i++)
  151. servicePoints.Remove (toRemove [i]);
  152. if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
  153. return;
  154. // get rid of the ones with the longest idle time
  155. SortedList list = new SortedList (servicePoints.Count);
  156. e = servicePoints.GetEnumerator ();
  157. while (e.MoveNext ()) {
  158. ServicePoint sp = (ServicePoint) e.Value;
  159. if (sp.CurrentConnections == 0) {
  160. while (list.ContainsKey (sp.IdleSince))
  161. sp.IdleSince.AddMilliseconds (1);
  162. list.Add (sp.IdleSince, sp.Address);
  163. }
  164. }
  165. for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
  166. servicePoints.Remove (list.GetByIndex (i));
  167. }
  168. }
  169. }
  170. }