2003-10-10 Pedro Mart�nez Juli� <yoros@wanadoo.es>
[mono.git] / mcs / class / System / System.Net / ServicePointManager.cs
1 //\r
2 // System.Net.ServicePointManager\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7 \r
8 using System;\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
14 \r
15 //\r
16 // notes:\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
22 // \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
30 //\r
31 \r
32 \r
33 namespace System.Net \r
34 {\r
35         class DummyPolicy : ICertificatePolicy\r
36         {\r
37                 public bool CheckValidationResult (ServicePoint point,\r
38                                                    X509Certificate certificate,\r
39                                                    WebRequest request,\r
40                                                    int certificateProblem)\r
41                 {\r
42                         return (certificateProblem == 0);\r
43                 }\r
44         }\r
45         \r
46         public class ServicePointManager\r
47         {\r
48                 private static HybridDictionary servicePoints = new HybridDictionary ();\r
49                 \r
50                 // Static properties\r
51                 \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
56                 \r
57                 // Fields\r
58                 \r
59                 public const int DefaultNonPersistentConnectionLimit = 4;\r
60                 public const int DefaultPersistentConnectionLimit = 2;\r
61 \r
62                 const string configKey = "system.net/connectionManagement";\r
63                 static Hashtable config;\r
64                 \r
65                 static ServicePointManager ()\r
66                 {\r
67                         ConnectionManagementData manager;\r
68                         manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);\r
69                         config = manager.Data;\r
70                 }\r
71                 // Constructors\r
72                 private ServicePointManager ()\r
73                 {\r
74                 }               \r
75                 \r
76                 // Properties\r
77                 \r
78                 public static ICertificatePolicy CertificatePolicy {\r
79                         get { return policy; }\r
80                         set { policy = value; }\r
81                 }\r
82                 \r
83                 public static int DefaultConnectionLimit {\r
84                         get { return defaultConnectionLimit; }\r
85                         set { \r
86                                 if (value <= 0)\r
87                                         throw new ArgumentOutOfRangeException ("value");\r
88 \r
89                                 defaultConnectionLimit = value; \r
90                         }\r
91                 }\r
92                 \r
93                 public static int MaxServicePointIdleTime {\r
94                         get { \r
95                                 return maxServicePointIdleTime;\r
96                         }\r
97                         set { \r
98                                 if (value < -2 || value > Int32.MaxValue)\r
99                                         throw new ArgumentOutOfRangeException ("value");\r
100                                 maxServicePointIdleTime = value;\r
101                         }\r
102                 }\r
103                 \r
104                 public static int MaxServicePoints {\r
105                         get { \r
106                                 return maxServicePoints; \r
107                         }\r
108                         set {  \r
109                                 if (value < 0)\r
110                                         throw new ArgumentException ("value");                          \r
111 \r
112                                 maxServicePoints = value;\r
113                                 RecycleServicePoints ();\r
114                         }\r
115                 }\r
116                 \r
117                 // Methods\r
118                 \r
119                 public static ServicePoint FindServicePoint (Uri address) \r
120                 {\r
121                         return FindServicePoint (address, GlobalProxySelection.Select);\r
122                 }\r
123                 \r
124                 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)\r
125                 {\r
126                         return FindServicePoint (new Uri(uriString), proxy);\r
127                 }\r
128                 \r
129                 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)\r
130                 {\r
131                         if (address == null)\r
132                                 throw new ArgumentNullException ("address");\r
133 \r
134                         RecycleServicePoints ();\r
135                         \r
136                         bool usesProxy = false;\r
137                         if (proxy != null && !proxy.IsBypassed(address)) {\r
138                                 usesProxy = true;\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
142                         } \r
143 \r
144                         address = new Uri (address.Scheme + "://" + address.Authority);\r
145                         \r
146                         ServicePoint sp = null;\r
147                         lock (servicePoints) {\r
148                                 sp = servicePoints [address] as ServicePoint;\r
149                                 if (sp != null)\r
150                                         return sp;\r
151 \r
152                                 if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)\r
153                                         throw new InvalidOperationException ("maximum number of service points reached");\r
154 \r
155                                 string addr = address.ToString ();\r
156                                 int limit = defaultConnectionLimit;\r
157                                 if (config.Contains (addr))\r
158                                         limit = (int) config [addr];\r
159                                 \r
160                                 sp = new ServicePoint (address, limit, maxServicePointIdleTime);\r
161                                 sp.UsesProxy = usesProxy;\r
162                                 servicePoints.Add (address, sp);\r
163                         }\r
164                         \r
165                         return sp;\r
166                 }\r
167                 \r
168                 // Internal Methods\r
169 \r
170                 internal static void RecycleServicePoints ()\r
171                 {\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
180                                         }\r
181                                 }\r
182                                 \r
183                                 for (int i = 0; i < toRemove.Count; i++) \r
184                                         servicePoints.Remove (toRemove [i]);\r
185 \r
186                                 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)\r
187                                         return;\r
188 \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
198                                         }\r
199                                 }\r
200                                 \r
201                                 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)\r
202                                         servicePoints.Remove (list.GetByIndex (i));\r
203                         }\r
204                 }\r
205         }\r
206 }\r