Flush (work in progress)
[mono.git] / mcs / class / System / System.Net / ServicePoint.cs
1 //
2 // System.Net.ServicePoint
3 //
4 // Authors:
5 //      Lawrence Pit (loz@cable.a2000.nl)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2002 Lawrence Pit
9 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Net.Sockets;
36 using System.Security.Cryptography.X509Certificates;
37 using System.Threading;
38
39 namespace System.Net 
40 {
41         public class ServicePoint
42         {
43                 Uri uri;
44                 int connectionLimit;
45                 int maxIdleTime;
46                 int currentConnections;
47                 DateTime idleSince;
48                 Version protocolVersion;
49                 X509Certificate certificate;
50                 X509Certificate clientCertificate;
51                 IPHostEntry host;
52                 bool usesProxy;
53                 Hashtable groups;
54                 bool sendContinue = true;
55                 bool useConnect;
56                 object locker = new object ();
57                 object hostE = new object ();
58 #if NET_1_1
59                 bool useNagle;
60 #endif
61 #if NET_2_0
62                 BindIPEndPoint endPointCallback = null;
63 #endif
64                 
65                 // Constructors
66
67                 internal ServicePoint (Uri uri, int connectionLimit, int maxIdleTime)
68                 {
69                         this.uri = uri;  
70                         this.connectionLimit = connectionLimit;
71                         this.maxIdleTime = maxIdleTime;                 
72                         this.currentConnections = 0;
73                         this.idleSince = DateTime.Now;
74                 }
75                 
76                 // Properties
77                 
78                 public Uri Address {
79                         get { return uri; }
80                 }
81
82 #if NET_2_0
83                 static Exception GetMustImplement ()
84                 {
85                         return new NotImplementedException ();
86                 }
87
88                 public BindIPEndPoint BindIPEndPointDelegate
89                 {
90                         get { return endPointCallback; }
91                         set { endPointCallback = value; }
92                 }
93 #endif
94                 
95                 public X509Certificate Certificate {
96                         get { return certificate; }
97                 }
98                 
99                 public X509Certificate ClientCertificate {
100                         get { return clientCertificate; }
101                 }
102
103 #if NET_2_0
104                 [MonoTODO]
105                 public int ConnectionLeaseTimeout
106                 {
107                         get {
108                                 throw GetMustImplement ();
109                         }
110                         set {
111                                 throw GetMustImplement ();
112                         }
113                 }
114 #endif
115                 
116                 public int ConnectionLimit {
117                         get { return connectionLimit; }
118                         set {
119                                 if (value <= 0)
120                                         throw new ArgumentOutOfRangeException ();
121
122                                 connectionLimit = value;
123                         }
124                 }
125                 
126                 public string ConnectionName {
127                         get { return uri.Scheme; }
128                 }
129
130                 public int CurrentConnections {
131                         get {
132                                 return currentConnections;
133                         }
134                 }
135
136                 public DateTime IdleSince {
137                         get {
138                                 return idleSince;
139                         }
140                         internal set {
141                                 lock (locker)
142                                         idleSince = value;
143                         }
144                 }
145                 
146                 public int MaxIdleTime {
147                         get { return maxIdleTime; }
148                         set { 
149                                 if (value < Timeout.Infinite || value > Int32.MaxValue)
150                                         throw new ArgumentOutOfRangeException ();
151                                 this.maxIdleTime = value; 
152                         }
153                 }
154                 
155                 public virtual Version ProtocolVersion {
156                         get { return protocolVersion; }
157                 }
158
159 #if NET_2_0
160                 [MonoTODO]
161                 public int ReceiveBufferSize
162                 {
163                         get {
164                                 throw GetMustImplement ();
165                         }
166                         set {
167                                 throw GetMustImplement ();
168                         }
169                 }
170 #endif
171                 
172                 public bool SupportsPipelining {
173                         get { return HttpVersion.Version11.Equals (protocolVersion); }
174                 }
175
176 #if NET_1_1
177                 public bool Expect100Continue {
178                         get { return SendContinue; }
179                         set { SendContinue = value; }
180                 }
181
182                 public bool UseNagleAlgorithm {
183                         get { return useNagle; }
184                         set { useNagle = value; }
185                 }
186 #endif
187
188                 internal bool SendContinue {
189                         get { return sendContinue &&
190                                      (protocolVersion == null || protocolVersion == HttpVersion.Version11); }
191                         set { sendContinue = value; }
192                 }
193                 // Methods
194                 
195 #if !NET_2_0
196                 public override int GetHashCode() 
197                 {
198                         return base.GetHashCode ();
199                 }
200 #endif
201                 
202                 // Internal Methods
203
204                 internal bool UsesProxy {
205                         get { return usesProxy; }
206                         set { usesProxy = value; }
207                 }
208
209                 internal bool UseConnect {
210                         get { return useConnect; }
211                         set { useConnect = value; }
212                 }
213
214                 internal bool AvailableForRecycling {
215                         get { 
216                                 return CurrentConnections == 0
217                                     && maxIdleTime != Timeout.Infinite
218                                     && DateTime.Now >= IdleSince.AddMilliseconds (maxIdleTime);
219                         }
220                 }
221
222                 internal Hashtable Groups {
223                         get {
224                                 if (groups == null)
225                                         groups = new Hashtable ();
226
227                                 return groups;
228                         }
229                 }
230
231                 internal IPHostEntry HostEntry
232                 {
233                         get {
234                                 lock (hostE) {
235                                         if (host != null)
236                                                 return host;
237
238                                         string uriHost = uri.Host;
239
240                                         // There is no need to do DNS resolution on literal IP addresses
241                                         if (uri.HostNameType == UriHostNameType.IPv6 ||
242                                                 uri.HostNameType == UriHostNameType.IPv4) {
243
244                                                 if (uri.HostNameType == UriHostNameType.IPv6) {
245                                                         // Remove square brackets
246                                                         uriHost = uriHost.Substring(1,uriHost.Length-2);
247                                                 }
248
249                                                 // Creates IPHostEntry
250                                                 host = new IPHostEntry();
251                                                 host.AddressList = new IPAddress[] { IPAddress.Parse(uriHost) };
252
253                                                 return host;
254                                         }
255
256                                         // Try DNS resolution on host names
257                                         try  {
258                                                 host = Dns.GetHostByName (uriHost);
259                                         } 
260                                         catch {
261                                                 return null;
262                                         }
263                                 }
264
265                                 return host;
266                         }
267                 }
268
269                 internal void SetVersion (Version version)
270                 {
271                         protocolVersion = version;
272                 }
273
274 #if !TARGET_JVM
275                 WebConnectionGroup GetConnectionGroup (string name)
276                 {
277                         if (name == null)
278                                 name = "";
279
280                         WebConnectionGroup group = Groups [name] as WebConnectionGroup;
281                         if (group != null)
282                                 return group;
283
284                         group = new WebConnectionGroup (this, name);
285                         Groups [name] = group;
286                         return group;
287                 }
288
289                 internal EventHandler SendRequest (HttpWebRequest request, string groupName)
290                 {
291                         WebConnection cnc;
292                         
293                         lock (locker) {
294                                 WebConnectionGroup cncGroup = GetConnectionGroup (groupName);
295                                 cnc = cncGroup.GetConnection (request);
296                         }
297                         
298                         return cnc.SendRequest (request);
299                 }
300 #endif
301 #if NET_2_0
302                 public bool CloseConnectionGroup (string connectionGroupName)
303                 {
304                         lock (locker) {
305                                 WebConnectionGroup cncGroup = GetConnectionGroup (connectionGroupName);
306                                 if (cncGroup != null) {
307                                         cncGroup.Close ();
308                                         return true;
309                                 }
310                         }
311
312                         return false;
313                 }
314 #endif
315
316                 internal void IncrementConnection ()
317                 {
318                         lock (locker) {
319                                 currentConnections++;
320                                 idleSince = DateTime.Now.AddMilliseconds (1000000);
321                         }
322                 }
323
324                 internal void DecrementConnection ()
325                 {
326                         lock (locker) {
327                                 currentConnections--;
328                                 if (currentConnections == 0)
329                                         idleSince = DateTime.Now;
330                         }
331                 }
332
333                 internal void SetCertificates (X509Certificate client, X509Certificate server) 
334                 {
335                         certificate = server;
336                         clientCertificate = client;
337                 }
338
339 #if NET_2_0
340                 internal bool CallEndPointDelegate (Socket sock, IPEndPoint remote)
341                 {
342                         if (endPointCallback == null)
343                                 return true;
344
345                         int count = 0;
346                         for (;;) {
347                                 IPEndPoint local = null;
348                                 try {
349                                         local = endPointCallback (this,
350                                                 remote, count);
351                                 } catch {
352                                         // This is to differentiate from an
353                                         // OverflowException, which should propagate.
354                                         return false;
355                                 }
356
357                                 if (local == null)
358                                         return true;
359
360                                 try {
361                                         sock.Bind (local);
362                                 } catch (SocketException) {
363                                         // This is intentional; the docs say
364                                         // that if the Bind fails, we keep
365                                         // going until there is an
366                                         // OverflowException on the retry
367                                         // count.
368                                         checked { ++count; }
369                                         continue;
370                                 }
371
372                                 return true;
373                         }
374                 }
375 #endif
376         }
377 }
378
379