ServicePointManager.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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 ConnectionManagementData manager;
  54. static ServicePointManager ()
  55. {
  56. manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
  57. }
  58. // Constructors
  59. private ServicePointManager ()
  60. {
  61. }
  62. // Properties
  63. public static ICertificatePolicy CertificatePolicy {
  64. get { return policy; }
  65. set { policy = value; }
  66. }
  67. public static int DefaultConnectionLimit {
  68. get { return defaultConnectionLimit; }
  69. set {
  70. if (value <= 0)
  71. throw new ArgumentOutOfRangeException ("value");
  72. defaultConnectionLimit = value;
  73. }
  74. }
  75. public static int MaxServicePointIdleTime {
  76. get {
  77. return maxServicePointIdleTime;
  78. }
  79. set {
  80. if (value < -2 || value > Int32.MaxValue)
  81. throw new ArgumentOutOfRangeException ("value");
  82. maxServicePointIdleTime = value;
  83. }
  84. }
  85. public static int MaxServicePoints {
  86. get {
  87. return maxServicePoints;
  88. }
  89. set {
  90. if (value < 0)
  91. throw new ArgumentException ("value");
  92. maxServicePoints = value;
  93. RecycleServicePoints ();
  94. }
  95. }
  96. // Methods
  97. public static ServicePoint FindServicePoint (Uri address)
  98. {
  99. return FindServicePoint (address, GlobalProxySelection.Select);
  100. }
  101. public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
  102. {
  103. return FindServicePoint (new Uri(uriString), proxy);
  104. }
  105. public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
  106. {
  107. if (address == null)
  108. throw new ArgumentNullException ("address");
  109. RecycleServicePoints ();
  110. bool usesProxy = false;
  111. if (proxy != null && !proxy.IsBypassed(address)) {
  112. usesProxy = true;
  113. address = proxy.GetProxy (address);
  114. if (address.Scheme != "http" && address.Scheme != "https")
  115. throw new NotSupportedException ("Proxy scheme not supported.");
  116. }
  117. address = new Uri (address.Scheme + "://" + address.Authority);
  118. ServicePoint sp = null;
  119. lock (servicePoints) {
  120. sp = servicePoints [address] as ServicePoint;
  121. if (sp != null)
  122. return sp;
  123. if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
  124. throw new InvalidOperationException ("maximum number of service points reached");
  125. string addr = address.ToString ();
  126. int limit = (int) manager.GetMaxConnections (addr);
  127. sp = new ServicePoint (address, limit, maxServicePointIdleTime);
  128. sp.UsesProxy = usesProxy;
  129. servicePoints.Add (address, sp);
  130. }
  131. return sp;
  132. }
  133. // Internal Methods
  134. internal static void RecycleServicePoints ()
  135. {
  136. ArrayList toRemove = new ArrayList ();
  137. lock (servicePoints) {
  138. IDictionaryEnumerator e = servicePoints.GetEnumerator ();
  139. while (e.MoveNext ()) {
  140. ServicePoint sp = (ServicePoint) e.Value;
  141. if (sp.AvailableForRecycling) {
  142. toRemove.Add (e.Key);
  143. }
  144. }
  145. for (int i = 0; i < toRemove.Count; i++)
  146. servicePoints.Remove (toRemove [i]);
  147. if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
  148. return;
  149. // get rid of the ones with the longest idle time
  150. SortedList list = new SortedList (servicePoints.Count);
  151. e = servicePoints.GetEnumerator ();
  152. while (e.MoveNext ()) {
  153. ServicePoint sp = (ServicePoint) e.Value;
  154. if (sp.CurrentConnections == 0) {
  155. while (list.ContainsKey (sp.IdleSince))
  156. sp.IdleSince.AddMilliseconds (1);
  157. list.Add (sp.IdleSince, sp.Address);
  158. }
  159. }
  160. for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
  161. servicePoints.Remove (list.GetByIndex (i));
  162. }
  163. }
  164. }
  165. }