System.Drawing: added email to icon and test file headers
[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                 bool useNagle;
59                 BindIPEndPoint endPointCallback = null;
60                 bool tcp_keepalive;
61                 int tcp_keepalive_time;
62                 int tcp_keepalive_interval;
63                 
64                 // Constructors
65
66                 internal ServicePoint (Uri uri, int connectionLimit, int maxIdleTime)
67                 {
68                         this.uri = uri;  
69                         this.connectionLimit = connectionLimit;
70                         this.maxIdleTime = maxIdleTime;                 
71                         this.currentConnections = 0;
72                         this.idleSince = DateTime.Now;
73                 }
74                 
75                 // Properties
76                 
77                 public Uri Address {
78                         get { return uri; }
79                 }
80
81 #if NET_2_0
82                 static Exception GetMustImplement ()
83                 {
84                         return new NotImplementedException ();
85                 }
86
87                 public BindIPEndPoint BindIPEndPointDelegate
88                 {
89                         get { return endPointCallback; }
90                         set { endPointCallback = value; }
91                 }
92 #endif
93                 
94                 public X509Certificate Certificate {
95                         get { return certificate; }
96                 }
97                 
98                 public X509Certificate ClientCertificate {
99                         get { return clientCertificate; }
100                 }
101
102 #if NET_2_0
103                 [MonoTODO]
104                 public int ConnectionLeaseTimeout
105                 {
106                         get {
107                                 throw GetMustImplement ();
108                         }
109                         set {
110                                 throw GetMustImplement ();
111                         }
112                 }
113 #endif
114                 
115                 public int ConnectionLimit {
116                         get { return connectionLimit; }
117                         set {
118                                 if (value <= 0)
119                                         throw new ArgumentOutOfRangeException ();
120
121                                 connectionLimit = value;
122                         }
123                 }
124                 
125                 public string ConnectionName {
126                         get { return uri.Scheme; }
127                 }
128
129                 public int CurrentConnections {
130                         get {
131                                 return currentConnections;
132                         }
133                 }
134
135                 public DateTime IdleSince {
136                         get {
137                                 return idleSince;
138                         }
139                         internal set {
140                                 lock (locker)
141                                         idleSince = value;
142                         }
143                 }
144                 
145                 public int MaxIdleTime {
146                         get { return maxIdleTime; }
147                         set { 
148                                 if (value < Timeout.Infinite || value > Int32.MaxValue)
149                                         throw new ArgumentOutOfRangeException ();
150                                 this.maxIdleTime = value; 
151                         }
152                 }
153                 
154                 public virtual Version ProtocolVersion {
155                         get { return protocolVersion; }
156                 }
157
158 #if NET_2_0
159                 [MonoTODO]
160                 public int ReceiveBufferSize
161                 {
162                         get {
163                                 throw GetMustImplement ();
164                         }
165                         set {
166                                 throw GetMustImplement ();
167                         }
168                 }
169 #endif
170                 
171                 public bool SupportsPipelining {
172                         get { return HttpVersion.Version11.Equals (protocolVersion); }
173                 }
174
175 #if NET_1_1
176                 public bool Expect100Continue {
177                         get { return SendContinue; }
178                         set { SendContinue = value; }
179                 }
180
181                 public bool UseNagleAlgorithm {
182                         get { return useNagle; }
183                         set { useNagle = value; }
184                 }
185 #endif
186
187                 internal bool SendContinue {
188                         get { return sendContinue &&
189                                      (protocolVersion == null || protocolVersion == HttpVersion.Version11); }
190                         set { sendContinue = value; }
191                 }
192                 // Methods
193
194                 public void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
195                 {
196                         if (enabled) {
197                                 if (keepAliveTime <= 0)
198                                         throw new ArgumentOutOfRangeException ("keepAliveTime", "Must be greater than 0");
199                                 if (keepAliveInterval <= 0)
200                                         throw new ArgumentOutOfRangeException ("keepAliveInterval", "Must be greater than 0");
201                         }
202
203                         tcp_keepalive = enabled;
204                         tcp_keepalive_time = keepAliveTime;
205                         tcp_keepalive_interval = keepAliveInterval;
206                 }
207
208                 internal void KeepAliveSetup (Socket socket)
209                 {
210                         if (!tcp_keepalive)
211                                 return;
212
213                         byte [] bytes = new byte [12];
214                         PutBytes (bytes, (uint) (tcp_keepalive ? 1 : 0), 0);
215                         PutBytes (bytes, (uint) tcp_keepalive_time, 4);
216                         PutBytes (bytes, (uint) tcp_keepalive_interval, 8);
217                         socket.IOControl (IOControlCode.KeepAliveValues, bytes, null);
218                 }
219
220                 static void PutBytes (byte [] bytes, uint v, int offset)
221                 {
222                         if (BitConverter.IsLittleEndian) {
223                                 bytes [offset] = (byte) (v & 0x000000ff);
224                                 bytes [offset + 1] = (byte) ((v & 0x0000ff00) >> 8);
225                                 bytes [offset + 2] = (byte) ((v & 0x00ff0000) >> 16);
226                                 bytes [offset + 3] = (byte) ((v & 0xff000000) >> 24);
227                         } else {
228                                 bytes [offset + 3] = (byte) (v & 0x000000ff);
229                                 bytes [offset + 2] = (byte) ((v & 0x0000ff00) >> 8);
230                                 bytes [offset + 1] = (byte) ((v & 0x00ff0000) >> 16);
231                                 bytes [offset] = (byte) ((v & 0xff000000) >> 24);
232                         }
233                 }
234
235 #if !NET_2_0
236                 public override int GetHashCode() 
237                 {
238                         return base.GetHashCode ();
239                 }
240 #endif
241                 
242                 // Internal Methods
243
244                 internal bool UsesProxy {
245                         get { return usesProxy; }
246                         set { usesProxy = value; }
247                 }
248
249                 internal bool UseConnect {
250                         get { return useConnect; }
251                         set { useConnect = value; }
252                 }
253
254                 internal bool AvailableForRecycling {
255                         get { 
256                                 return CurrentConnections == 0
257                                     && maxIdleTime != Timeout.Infinite
258                                     && DateTime.Now >= IdleSince.AddMilliseconds (maxIdleTime);
259                         }
260                 }
261
262                 internal Hashtable Groups {
263                         get {
264                                 if (groups == null)
265                                         groups = new Hashtable ();
266
267                                 return groups;
268                         }
269                 }
270
271                 internal IPHostEntry HostEntry
272                 {
273                         get {
274                                 lock (hostE) {
275                                         if (host != null)
276                                                 return host;
277
278                                         string uriHost = uri.Host;
279
280                                         // There is no need to do DNS resolution on literal IP addresses
281                                         if (uri.HostNameType == UriHostNameType.IPv6 ||
282                                                 uri.HostNameType == UriHostNameType.IPv4) {
283
284                                                 if (uri.HostNameType == UriHostNameType.IPv6) {
285                                                         // Remove square brackets
286                                                         uriHost = uriHost.Substring(1,uriHost.Length-2);
287                                                 }
288
289                                                 // Creates IPHostEntry
290                                                 host = new IPHostEntry();
291                                                 host.AddressList = new IPAddress[] { IPAddress.Parse(uriHost) };
292
293                                                 return host;
294                                         }
295
296                                         // Try DNS resolution on host names
297                                         try  {
298                                                 host = Dns.GetHostByName (uriHost);
299                                         } 
300                                         catch {
301                                                 return null;
302                                         }
303                                 }
304
305                                 return host;
306                         }
307                 }
308
309                 internal void SetVersion (Version version)
310                 {
311                         protocolVersion = version;
312                 }
313
314 #if !TARGET_JVM
315                 WebConnectionGroup GetConnectionGroup (string name)
316                 {
317                         if (name == null)
318                                 name = "";
319
320                         WebConnectionGroup group = Groups [name] as WebConnectionGroup;
321                         if (group != null)
322                                 return group;
323
324                         group = new WebConnectionGroup (this, name);
325                         Groups [name] = group;
326                         return group;
327                 }
328
329                 internal EventHandler SendRequest (HttpWebRequest request, string groupName)
330                 {
331                         WebConnection cnc;
332                         
333                         lock (locker) {
334                                 WebConnectionGroup cncGroup = GetConnectionGroup (groupName);
335                                 cnc = cncGroup.GetConnection (request);
336                         }
337                         
338                         return cnc.SendRequest (request);
339                 }
340 #endif
341 #if NET_2_0
342                 public bool CloseConnectionGroup (string connectionGroupName)
343                 {
344                         lock (locker) {
345                                 WebConnectionGroup cncGroup = GetConnectionGroup (connectionGroupName);
346                                 if (cncGroup != null) {
347                                         cncGroup.Close ();
348                                         return true;
349                                 }
350                         }
351
352                         return false;
353                 }
354 #endif
355
356                 internal void IncrementConnection ()
357                 {
358                         lock (locker) {
359                                 currentConnections++;
360                                 idleSince = DateTime.Now.AddMilliseconds (1000000);
361                         }
362                 }
363
364                 internal void DecrementConnection ()
365                 {
366                         lock (locker) {
367                                 currentConnections--;
368                                 if (currentConnections == 0)
369                                         idleSince = DateTime.Now;
370                         }
371                 }
372
373                 internal void SetCertificates (X509Certificate client, X509Certificate server) 
374                 {
375                         certificate = server;
376                         clientCertificate = client;
377                 }
378
379 #if NET_2_0
380                 internal bool CallEndPointDelegate (Socket sock, IPEndPoint remote)
381                 {
382                         if (endPointCallback == null)
383                                 return true;
384
385                         int count = 0;
386                         for (;;) {
387                                 IPEndPoint local = null;
388                                 try {
389                                         local = endPointCallback (this,
390                                                 remote, count);
391                                 } catch {
392                                         // This is to differentiate from an
393                                         // OverflowException, which should propagate.
394                                         return false;
395                                 }
396
397                                 if (local == null)
398                                         return true;
399
400                                 try {
401                                         sock.Bind (local);
402                                 } catch (SocketException) {
403                                         // This is intentional; the docs say
404                                         // that if the Bind fails, we keep
405                                         // going until there is an
406                                         // OverflowException on the retry
407                                         // count.
408                                         checked { ++count; }
409                                         continue;
410                                 }
411
412                                 return true;
413                         }
414                 }
415 #endif
416         }
417 }
418
419