**** Merged from MCS ****
[mono-project.git] / mcs / class / System / System.Net.Sockets / TcpClient.cs
blob7a367fa07f708d48f2e3e428330fd703516dde8d
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 //
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.
31 // NB: This is untested (probably buggy) code - take care if using it
33 using System;
34 using System.Net;
36 namespace System.Net.Sockets
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
44 // private data
46 private NetworkStream stream;
47 private bool active;
48 private Socket client;
49 private bool disposed = false;
51 // constructor
53 /// <summary>
54 /// Some code that is shared between the constructors.
55 /// </summary>
56 private void Init (AddressFamily family)
58 active = false;
60 if(client != null) {
61 client.Close();
62 client = null;
65 client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
68 /// <summary>
69 /// Constructs a new TcpClient with no connection set up
70 /// </summary>
71 public TcpClient ()
73 Init(AddressFamily.InterNetwork);
74 client.Bind(new IPEndPoint(IPAddress.Any, 0));
77 #if NET_1_1
78 public TcpClient (AddressFamily family)
80 if (family != AddressFamily.InterNetwork &&
81 family != AddressFamily.InterNetworkV6) {
82 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
85 Init (family);
86 client.Bind (new IPEndPoint (IPAddress.Any, 0));
88 #endif
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)
99 Init(local_end_point.AddressFamily);
100 client.Bind(local_end_point);
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)
113 Connect(hostname, port);
116 /// <summary>
117 /// A flag that is 'true' if the TcpClient has an active connection
118 /// </summary>
119 protected bool Active
121 get { return active; }
122 set { active = value; }
125 /// <summary>
126 /// The socket that all network comms passes through
127 /// </summary>
128 protected Socket Client
130 get { return client; }
131 set {
132 client = value;
133 stream = null;
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)
145 Client = s;
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
155 get {
156 return (LingerOption)client.GetSocketOption(
157 SocketOptionLevel.Socket,
158 SocketOptionName.Linger);
160 set {
161 client.SetSocketOption(
162 SocketOptionLevel.Socket,
163 SocketOptionName.Linger, value);
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
176 get {
177 return (bool)client.GetSocketOption(
178 SocketOptionLevel.Tcp,
179 SocketOptionName.NoDelay);
181 set {
182 client.SetSocketOption(
183 SocketOptionLevel.Tcp,
184 SocketOptionName.NoDelay, value);
188 /// <summary>
189 /// How big the receive buffer is (from the connection socket)
190 /// </summary>
191 public int ReceiveBufferSize
193 get {
194 return (int)client.GetSocketOption(
195 SocketOptionLevel.Socket,
196 SocketOptionName.ReceiveBuffer);
198 set {
199 client.SetSocketOption(
200 SocketOptionLevel.Socket,
201 SocketOptionName.ReceiveBuffer, value);
205 /// <summary>
206 /// How long before the socket will time out on a
207 /// Receive() call
208 /// </summary>
209 public int ReceiveTimeout
211 get {
212 return (int)client.GetSocketOption(
213 SocketOptionLevel.Socket,
214 SocketOptionName.ReceiveTimeout);
216 set {
217 client.SetSocketOption(
218 SocketOptionLevel.Socket,
219 SocketOptionName.ReceiveTimeout, value);
223 /// <summary>
224 /// How big the send buffer is (from the connection socket)
225 /// </summary>
226 public int SendBufferSize
228 get {
229 return (int)client.GetSocketOption(
230 SocketOptionLevel.Socket,
231 SocketOptionName.SendBuffer);
233 set {
234 client.SetSocketOption(
235 SocketOptionLevel.Socket,
236 SocketOptionName.SendBuffer, value);
240 /// <summary>
241 /// How long before the socket will time out on a
242 /// Send() call
243 /// </summary>
244 public int SendTimeout
246 get {
247 return (int)client.GetSocketOption(
248 SocketOptionLevel.Socket,
249 SocketOptionName.SendTimeout);
251 set {
252 client.SetSocketOption(
253 SocketOptionLevel.Socket,
254 SocketOptionName.SendTimeout, value);
259 // methods
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 ()
269 ((IDisposable) this).Dispose ();
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)
281 try {
282 client.Connect(remote_end_point);
283 stream = new NetworkStream(client, true);
284 active = true;
285 } finally {
286 CheckDisposed ();
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)
300 Connect(new IPEndPoint(address, port));
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)
315 CheckDisposed ();
317 IPHostEntry host = Dns.GetHostByName(hostname);
319 for(int i=0; i<host.AddressList.Length; i++)
321 try {
322 Init(host.AddressList[i].AddressFamily);
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
331 Connect(new IPEndPoint(host.AddressList[i], port));
332 break;
334 catch(Exception e) {
335 if(client != null) {
336 client.Close();
337 client = null;
340 /// This is the last known address, re-throw the exception
341 if(i == host.AddressList.Length-1)
342 throw e;
347 /// <summary>
348 /// Gets rid of all managed resources
349 /// </summary>
350 void IDisposable.Dispose ()
352 Dispose (true);
353 GC.SuppressFinalize (this);
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)
363 if (disposed)
364 return;
365 disposed = true;
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 ();
380 client = null;
384 /// <summary>
385 /// Destructor - just calls Dispose()
386 /// </summary>
387 ~TcpClient ()
389 Dispose (false);
392 /// <returns>A NetworkStream object connected to the
393 /// connection socket</returns>
394 public NetworkStream GetStream()
396 try {
397 if (stream == null)
399 stream = new NetworkStream (client, true);
401 return stream;
403 finally { CheckDisposed (); }
406 private void CheckDisposed ()
408 if (disposed)
409 throw new ObjectDisposedException (GetType().FullName);