2 // System.Net.ServicePointManager
\r
5 // Lawrence Pit (loz@cable.a2000.nl)
\r
9 using System.Collections;
\r
10 using System.Collections.Specialized;
\r
11 using System.Configuration;
\r
12 using System.Net.Configuration;
\r
13 using System.Security.Cryptography.X509Certificates;
\r
17 // A service point manager manages service points (duh!).
\r
18 // A service point maintains a list of connections (per scheme + authority).
\r
19 // According to HttpWebRequest.ConnectionGroupName each connection group
\r
20 // creates additional connections. therefor, a service point has a hashtable
\r
21 // of connection groups where each value is a list of connections.
\r
23 // when we need to make an HttpWebRequest, we need to do the following:
\r
24 // 1. find service point, given Uri and Proxy
\r
25 // 2. find connection group, given service point and group name
\r
26 // 3. find free connection in connection group, or create one (if ok due to limits)
\r
27 // 4. lease connection
\r
28 // 5. execute request
\r
29 // 6. when finished, return connection
\r
33 namespace System.Net
\r
35 class DummyPolicy : ICertificatePolicy
\r
37 public bool CheckValidationResult (ServicePoint point,
\r
38 X509Certificate certificate,
\r
40 int certificateProblem)
\r
42 return (certificateProblem == 0);
\r
46 public class ServicePointManager
\r
48 private static HybridDictionary servicePoints = new HybridDictionary ();
\r
50 // Static properties
\r
52 private static ICertificatePolicy policy = new DummyPolicy ();
\r
53 private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
\r
54 private static int maxServicePointIdleTime = 900000; // 15 minutes
\r
55 private static int maxServicePoints = 0;
\r
59 public const int DefaultNonPersistentConnectionLimit = 4;
\r
60 public const int DefaultPersistentConnectionLimit = 2;
\r
62 const string configKey = "system.net/connectionManagement";
\r
63 static Hashtable config;
\r
65 static ServicePointManager ()
\r
67 ConnectionManagementData manager;
\r
68 manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
\r
69 config = manager.Data;
\r
72 private ServicePointManager ()
\r
78 public static ICertificatePolicy CertificatePolicy {
\r
79 get { return policy; }
\r
80 set { policy = value; }
\r
83 public static int DefaultConnectionLimit {
\r
84 get { return defaultConnectionLimit; }
\r
87 throw new ArgumentOutOfRangeException ("value");
\r
89 defaultConnectionLimit = value;
\r
93 public static int MaxServicePointIdleTime {
\r
95 return maxServicePointIdleTime;
\r
98 if (value < -2 || value > Int32.MaxValue)
\r
99 throw new ArgumentOutOfRangeException ("value");
\r
100 maxServicePointIdleTime = value;
\r
104 public static int MaxServicePoints {
\r
106 return maxServicePoints;
\r
110 throw new ArgumentException ("value");
\r
112 maxServicePoints = value;
\r
113 RecycleServicePoints ();
\r
119 public static ServicePoint FindServicePoint (Uri address)
\r
121 return FindServicePoint (address, GlobalProxySelection.Select);
\r
124 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
\r
126 return FindServicePoint (new Uri(uriString), proxy);
\r
129 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
\r
131 if (address == null)
\r
132 throw new ArgumentNullException ("address");
\r
134 RecycleServicePoints ();
\r
136 bool usesProxy = false;
\r
137 if (proxy != null && !proxy.IsBypassed(address)) {
\r
139 address = proxy.GetProxy (address);
\r
140 if (address.Scheme != "http" && address.Scheme != "https")
\r
141 throw new NotSupportedException ("Proxy scheme not supported.");
\r
144 address = new Uri (address.Scheme + "://" + address.Authority);
\r
146 ServicePoint sp = null;
\r
147 lock (servicePoints) {
\r
148 sp = servicePoints [address] as ServicePoint;
\r
152 if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
\r
153 throw new InvalidOperationException ("maximum number of service points reached");
\r
155 string addr = address.ToString ();
\r
156 int limit = defaultConnectionLimit;
\r
157 if (config.Contains (addr))
\r
158 limit = (int) config [addr];
\r
160 sp = new ServicePoint (address, limit, maxServicePointIdleTime);
\r
161 sp.UsesProxy = usesProxy;
\r
162 servicePoints.Add (address, sp);
\r
168 // Internal Methods
\r
170 internal static void RecycleServicePoints ()
\r
172 ArrayList toRemove = new ArrayList ();
\r
173 lock (servicePoints) {
\r
174 IDictionaryEnumerator e = servicePoints.GetEnumerator ();
\r
175 while (e.MoveNext ()) {
\r
176 ServicePoint sp = (ServicePoint) e.Value;
\r
177 if (sp.AvailableForRecycling) {
\r
178 toRemove.Add (e.Key);
\r
179 Console.WriteLine ("Reciclo: {0}", e.Key);
\r
183 for (int i = 0; i < toRemove.Count; i++)
\r
184 servicePoints.Remove (toRemove [i]);
\r
186 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
\r
189 // get rid of the ones with the longest idle time
\r
190 SortedList list = new SortedList (servicePoints.Count);
\r
191 e = servicePoints.GetEnumerator ();
\r
192 while (e.MoveNext ()) {
\r
193 ServicePoint sp = (ServicePoint) e.Value;
\r
194 if (sp.CurrentConnections == 0) {
\r
195 while (list.ContainsKey (sp.IdleSince))
\r
196 sp.IdleSince.AddMilliseconds (1);
\r
197 list.Add (sp.IdleSince, sp.Address);
\r
201 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
\r
202 servicePoints.Remove (list.GetByIndex (i));
\r