ServicePointManager.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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.Security.Cryptography.X509Certificates;
  11. //
  12. // notes:
  13. // A service point manager manages service points (duh!).
  14. // A service point maintains a list of connections (per scheme + authority).
  15. // According to HttpWebRequest.ConnectionGroupName each connection group
  16. // creates additional connections. therefor, a service point has a hashtable
  17. // of connection groups where each value is a list of connections.
  18. //
  19. // when we need to make an HttpWebRequest, we need to do the following:
  20. // 1. find service point, given Uri and Proxy
  21. // 2. find connection group, given service point and group name
  22. // 3. find free connection in connection group, or create one (if ok due to limits)
  23. // 4. lease connection
  24. // 5. execute request
  25. // 6. when finished, return connection
  26. //
  27. namespace System.Net
  28. {
  29. public class ServicePointManager
  30. {
  31. private static HybridDictionary servicePoints = new HybridDictionary ();
  32. // Static properties
  33. private static ICertificatePolicy policy = null;
  34. private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
  35. private static int maxServicePointIdleTime = 900000; // 15 minutes
  36. private static int maxServicePoints = 0;
  37. // Fields
  38. public const int DefaultNonPersistentConnectionLimit = 4;
  39. public const int DefaultPersistentConnectionLimit = 2;
  40. // Constructors
  41. private ServicePointManager ()
  42. {
  43. }
  44. // Properties
  45. public static ICertificatePolicy CertificatePolicy {
  46. get { return policy; }
  47. set { policy = value; }
  48. }
  49. public static int DefaultConnectionLimit {
  50. get { return defaultConnectionLimit; }
  51. set {
  52. if (value < 0)
  53. throw new ArgumentOutOfRangeException ("value");
  54. defaultConnectionLimit = value;
  55. }
  56. }
  57. public static int MaxServicePointIdleTime {
  58. get {
  59. return maxServicePointIdleTime;
  60. }
  61. set {
  62. if (value < -2 || value > Int32.MaxValue)
  63. throw new ArgumentOutOfRangeException ("value");
  64. maxServicePointIdleTime = value;
  65. }
  66. }
  67. public static int MaxServicePoints {
  68. get {
  69. return maxServicePoints;
  70. }
  71. set {
  72. if (value < 0)
  73. throw new ArgumentException ("value");
  74. maxServicePoints = value;
  75. RecycleServicePoints ();
  76. }
  77. }
  78. // Methods
  79. public static ServicePoint FindServicePoint (Uri address)
  80. {
  81. return FindServicePoint (address, GlobalProxySelection.Select);
  82. }
  83. public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
  84. {
  85. return FindServicePoint (new Uri(uriString), proxy);
  86. }
  87. public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
  88. {
  89. RecycleServicePoints ();
  90. if (address == null)
  91. throw new ArgumentNullException ("address");
  92. if (proxy != null && !proxy.IsBypassed(address)) {
  93. address = proxy.GetProxy (address);
  94. }
  95. address = new Uri (address.Scheme + "://" + address.Authority);
  96. ServicePoint sp = null;
  97. lock (servicePoints) {
  98. sp = (ServicePoint) servicePoints [address];
  99. if (sp != null)
  100. return sp;
  101. if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
  102. throw new InvalidOperationException ("maximum number of service points reached");
  103. sp = new ServicePoint (address, defaultConnectionLimit, maxServicePointIdleTime);
  104. servicePoints.Add (address, sp);
  105. }
  106. return sp;
  107. }
  108. // Internal Methods
  109. internal static void RecycleServicePoints ()
  110. {
  111. ArrayList toRemove = new ArrayList ();
  112. lock (servicePoints) {
  113. IDictionaryEnumerator e = servicePoints.GetEnumerator ();
  114. while (e.MoveNext ()) {
  115. ServicePoint sp = (ServicePoint) e.Value;
  116. if (sp.AvailableForRecycling) {
  117. toRemove.Add (e.Key);
  118. }
  119. }
  120. for (int i = 0; i < toRemove.Count; i++)
  121. servicePoints.Remove (toRemove [i]);
  122. if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
  123. return;
  124. // get rid of the ones with the longest idle time
  125. SortedList list = new SortedList (servicePoints.Count);
  126. e = servicePoints.GetEnumerator ();
  127. while (e.MoveNext ()) {
  128. ServicePoint sp = (ServicePoint) e.Value;
  129. if (sp.CurrentConnections == 0) {
  130. while (list.ContainsKey (sp.IdleSince))
  131. sp.IdleSince.AddMilliseconds (1);
  132. list.Add (sp.IdleSince, sp.Address);
  133. }
  134. }
  135. for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
  136. servicePoints.Remove (list.GetByIndex (i));
  137. }
  138. }
  139. }
  140. }