remove svn:executable from .cs files
[mono.git] / mcs / class / System / System.Net.Sockets / TcpClient.cs
1 // System.Net.Sockets.TcpClient.cs
2 //
3 // Author:
4 //    Phillip Pearson (pp@myelin.co.nz)
5 //
6 // Copyright (C) 2001, Phillip Pearson
7 //    http://www.myelin.co.nz
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 // NB: This is untested (probably buggy) code - take care if using it
32
33 using System;
34 using System.Net;
35
36 namespace System.Net.Sockets
37 {
38         /// <remarks>
39         /// A slightly more abstracted way to create an
40         /// outgoing network connections than a Socket.
41         /// </remarks>
42         public class TcpClient : IDisposable
43         {
44                 // private data
45                 
46                 private NetworkStream stream;
47                 private bool active;
48                 private Socket client;
49                 private bool disposed = false;
50                 
51                 // constructor
52
53                 /// <summary>
54                 /// Some code that is shared between the constructors.
55                 /// </summary>
56                 private void Init (AddressFamily family)
57                 {
58                         active = false;
59
60                         if(client != null) {\r
61                                 client.Close();\r
62                                 client = null;\r
63                         }
64
65                         client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
66                 }
67
68                 /// <summary>
69                 /// Constructs a new TcpClient with no connection set up
70                 /// </summary>
71                 public TcpClient ()
72                 {
73                         Init(AddressFamily.InterNetwork);
74                         client.Bind(new IPEndPoint(IPAddress.Any, 0));
75                 }
76         
77 #if NET_1_1
78                 public TcpClient (AddressFamily family)
79                 {
80                         if (family != AddressFamily.InterNetwork &&
81                             family != AddressFamily.InterNetworkV6) {
82                                 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
83                         }
84                         
85                         Init (family);
86                         client.Bind (new IPEndPoint (IPAddress.Any, 0));
87                 }
88 #endif
89                 
90                 /// <summary>
91                 /// Constructs a new TcpClient with a specified local endpoint.
92                 /// Use this if you want to have your connections originating
93                 /// from a certain port, or a certain IP (on a multi homed
94                 /// system).
95                 /// </summary>
96                 /// <param name="local_end_point">The aforementioned local endpoint</param>
97                 public TcpClient (IPEndPoint local_end_point)
98                 {
99                         Init(local_end_point.AddressFamily);
100                         client.Bind(local_end_point);
101                 }
102                 
103                 /// <summary>
104                 /// Constructs a new TcpClient and connects to a specified
105                 /// host on a specified port.  A quick way to set up a network
106                 /// connection.
107                 /// </summary>
108                 /// <param name="hostname">The host to connect to, e.g.
109                 /// 192.168.0.201 or www.myelin.co.nz</param>
110                 /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
111                 public TcpClient (string hostname, int port)
112                 {
113                         Connect(hostname, port);
114                 }
115                                 
116                 /// <summary>
117                 /// A flag that is 'true' if the TcpClient has an active connection
118                 /// </summary>
119                 protected bool Active
120                 {
121                         get { return active; }
122                         set { active = value; }
123                 }
124                 
125                 /// <summary>
126                 /// The socket that all network comms passes through
127                 /// </summary>
128                 protected Socket Client
129                 {
130                         get { return client; }
131                         set {
132                                 client = value;
133                                 stream = null;
134                         }
135                 }
136
137                 /// <summary>
138                 /// Internal function to allow TcpListener.AcceptTcpClient
139                 /// to work (it needs to be able to set protected property
140                 /// 'Client')
141                 /// </summary>
142                 /// <param name="s"></param>
143                 internal void SetTcpClient (Socket s) 
144                 {
145                         Client = s;
146                 }
147                 
148                 /// <summary>
149                 /// If set, the socket will remain open after it has been
150                 /// instructed to close, in order to send data that remains
151                 /// in the buffer.
152                 /// </summary>
153                 public LingerOption LingerState
154                 {
155                         get {
156                                 return (LingerOption)client.GetSocketOption(
157                                         SocketOptionLevel.Socket,
158                                         SocketOptionName.Linger);
159                         }
160                         set {
161                                 client.SetSocketOption(
162                                         SocketOptionLevel.Socket,
163                                         SocketOptionName.Linger, value);
164                         }
165                 }
166                                 
167                 /// <summary>
168                 /// <p>If set, outbound data will be sent at once rather than collected
169                 /// until enough is available to fill a packet.</p>
170                 /// 
171                 /// <p>This is the TCP_NODELAY sockopt from BSD sockets and WinSock.
172                 /// For more information, look up the Nagle algorithm.</p>
173                 /// </summary>
174                 public bool NoDelay
175                 {
176                         get {
177                                 return (bool)client.GetSocketOption(
178                                         SocketOptionLevel.Tcp,
179                                         SocketOptionName.NoDelay);
180                         }
181                         set {
182                                 client.SetSocketOption(
183                                         SocketOptionLevel.Tcp,
184                                         SocketOptionName.NoDelay, value ? 1 : 0);
185                         }
186                 }
187                                 
188                 /// <summary>
189                 /// How big the receive buffer is (from the connection socket)
190                 /// </summary>
191                 public int ReceiveBufferSize
192                 {
193                         get {
194                                 return (int)client.GetSocketOption(
195                                         SocketOptionLevel.Socket,
196                                         SocketOptionName.ReceiveBuffer);
197                         }
198                         set {
199                                 client.SetSocketOption(
200                                         SocketOptionLevel.Socket,
201                                         SocketOptionName.ReceiveBuffer, value);
202                         }
203                 }
204                         
205                 /// <summary>
206                 /// How long before the socket will time out on a 
207                 /// Receive() call
208                 /// </summary>
209                 public int ReceiveTimeout
210                 {
211                         get {
212                                 return (int)client.GetSocketOption(
213                                         SocketOptionLevel.Socket,
214                                         SocketOptionName.ReceiveTimeout);
215                         }
216                         set {
217                                 client.SetSocketOption(
218                                         SocketOptionLevel.Socket,
219                                         SocketOptionName.ReceiveTimeout, value);
220                         }
221                 }
222                 
223                 /// <summary>
224                 /// How big the send buffer is (from the connection socket)
225                 /// </summary>
226                 public int SendBufferSize
227                 {
228                         get {
229                                 return (int)client.GetSocketOption(
230                                         SocketOptionLevel.Socket,
231                                         SocketOptionName.SendBuffer);
232                         }
233                         set {
234                                 client.SetSocketOption(
235                                         SocketOptionLevel.Socket,
236                                         SocketOptionName.SendBuffer, value);
237                         }
238                 }
239                 
240                 /// <summary>
241                 /// How long before the socket will time out on a
242                 /// Send() call
243                 /// </summary>
244                 public int SendTimeout
245                 {
246                         get {
247                                 return (int)client.GetSocketOption(
248                                         SocketOptionLevel.Socket,
249                                         SocketOptionName.SendTimeout);
250                         }
251                         set {
252                                 client.SetSocketOption(
253                                         SocketOptionLevel.Socket,
254                                         SocketOptionName.SendTimeout, value);
255                         }
256                 }
257                 
258                 
259                 // methods
260                 
261                 /// <summary>
262                 /// Closes the socket and disposes of all managed resources.
263                 /// 
264                 /// Throws SocketException if something goes wrong while
265                 /// closing the socket.
266                 /// </summary>
267                 public void Close ()
268                 {
269                         ((IDisposable) this).Dispose ();
270                 }
271                 
272                 /// <summary>
273                 /// Connects to a specified remote endpoint
274                 /// 
275                 /// Throws SocketException if something goes wrong while
276                 /// connecting.
277                 /// </summary>
278                 /// <param name="remote_end_point">The aforementioned endpoint</param>
279                 public void Connect (IPEndPoint remote_end_point)
280                 {
281                         try {
282                                 client.Connect(remote_end_point);
283                                 stream = new NetworkStream(client, true);
284                                 active = true;
285                         } finally {
286                                 CheckDisposed ();
287                         }
288                 }
289                 
290                 /// <summary>
291                 /// Connects to an IP address on a port
292                 /// 
293                 /// Throws SocketException if something goes wrong while
294                 /// connecting.
295                 /// </summary>
296                 /// <param name="address">The IP address (get it from Dns.GetHostByName)</param>
297                 /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
298                 public void Connect (IPAddress address, int port)
299                 {
300                         Connect(new IPEndPoint(address, port));
301                 }
302                 
303                 /// <summary>
304                 /// Resolves a fully qualified domain name to an IP address
305                 /// and connects to it on a specified port
306                 /// 
307                 /// Throws SocketException if something goes wrong while
308                 /// connecting.
309                 /// </summary>
310                 /// <param name="hostname">The hostname, e.g. www.myelin.co.nz</param>
311                 /// <param name="port">The port, e.g. 80 for HTTP</param>
312                 [MonoTODO]
313                 public void Connect (string hostname, int port)
314                 {
315                         CheckDisposed ();
316
317                         IPHostEntry host = Dns.GetHostByName(hostname);
318
319                         for(int i=0; i<host.AddressList.Length; i++)
320                         {\r
321                                 try {\r
322                                         Init(host.AddressList[i].AddressFamily);
323
324                                         if(host.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
325                                                 client.Bind(new IPEndPoint(IPAddress.Any, 0));
326 #if NET_1_1
327                                         else if(host.AddressList[i].AddressFamily == AddressFamily.InterNetworkV6)
328                                                 client.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
329 #endif
330
331                                         Connect(new IPEndPoint(host.AddressList[i], port));
332                                         break;
333                                 }\r
334                                 catch(Exception e) {\r
335                                         if(client != null) {\r
336                                                 client.Close();\r
337                                                 client = null;\r
338                                         }\r
339 \r
340                                         /// This is the last known address, re-throw the exception\r
341                                         if(i == host.AddressList.Length-1)\r
342                                                 throw e;\r
343                                 }\r
344                         }
345                 }
346                 
347                 /// <summary>
348                 /// Gets rid of all managed resources
349                 /// </summary>
350                 void IDisposable.Dispose ()
351                 {
352                         Dispose (true);
353                         GC.SuppressFinalize (this);
354                 }
355
356                 /// <summary>
357                 /// Gets rid of all unmanaged resources
358                 /// </summary>
359                 /// <param name="disposing">If this is true, it gets rid of all
360                 /// managed resources as well</param>
361                 protected virtual void Dispose (bool disposing)
362                 {
363                         if (disposed)
364                                 return;
365                         disposed = true;
366
367                         if (disposing){
368                                 // release managed resources
369                                 NetworkStream s = stream;
370                                 stream = null;
371                                 if (s != null) {
372                                         // This closes the socket as well, as the NetworkStream
373                                         // owns the socket.
374                                         s.Close();
375                                         active = false;
376                                         s = null;
377                                 } else if (client != null){
378                                         client.Close ();
379                                 }
380                                 client = null;
381                         }
382                 }
383                 
384                 /// <summary>
385                 /// Destructor - just calls Dispose()
386                 /// </summary>
387                 ~TcpClient ()
388                 {
389                         Dispose (false);
390                 }
391                 
392                 /// <returns>A NetworkStream object connected to the
393                 /// connection socket</returns>
394                 public NetworkStream GetStream()
395                 {
396                         try {
397                                 if (stream == null)
398                                 {
399                                         stream = new NetworkStream (client, true);
400                                 }
401                                 return stream;
402                         }
403                         finally { CheckDisposed (); }
404                 }
405                 
406                 private void CheckDisposed ()
407                 {
408                         if (disposed)
409                                 throw new ObjectDisposedException (GetType().FullName);
410                 }               
411         }
412 }