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