Merge pull request #3750 from marek-safar/socket
[mono-project.git] / mcs / class / System / System.Net.Sockets / TcpClient.cs
blobbbdb034aa1578de38196fdeb45f68f9e0e4a4958
1 // TcpClient.cs
2 //
3 // Author:
4 // Phillip Pearson (pp@myelin.co.nz)
5 // Gonzalo Paniagua Javier (gonzalo@novell.com)
6 // Sridhar Kulkarni (sridharkulkarni@gmail.com)
7 // Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright (C) 2001, Phillip Pearson http://www.myelin.co.nz
10 // Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
11 // Copyright 2011 Xamarin Inc.
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System;
36 using System.Net;
37 using System.Threading.Tasks;
39 namespace System.Net.Sockets
41 public class TcpClient : IDisposable {
42 enum Properties : uint {
43 LingerState = 1,
44 NoDelay = 2,
45 ReceiveBufferSize = 4,
46 ReceiveTimeout = 8,
47 SendBufferSize = 16,
48 SendTimeout = 32
51 // private data
52 NetworkStream stream;
53 bool active;
54 Socket client;
55 bool disposed;
56 Properties values;
57 int recv_timeout, send_timeout;
58 int recv_buffer_size, send_buffer_size;
59 LingerOption linger_state;
60 bool no_delay;
62 private void Init (AddressFamily family)
64 active = false;
66 if(client != null) {
67 client.Close();
68 client = null;
71 client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
74 public TcpClient ()
76 Init(AddressFamily.InterNetwork);
77 client.Bind(new IPEndPoint(IPAddress.Any, 0));
80 internal TcpClient (Socket s)
82 client = s;
85 public TcpClient (AddressFamily family)
87 if (family != AddressFamily.InterNetwork &&
88 family != AddressFamily.InterNetworkV6) {
89 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
92 Init (family);
93 IPAddress any = IPAddress.Any;
94 if (family == AddressFamily.InterNetworkV6)
95 any = IPAddress.IPv6Any;
96 client.Bind (new IPEndPoint (any, 0));
99 public TcpClient (IPEndPoint localEP)
101 Init (localEP.AddressFamily);
102 client.Bind (localEP);
105 public TcpClient (string hostname, int port)
107 Connect(hostname, port);
110 protected bool Active {
111 get { return active; }
112 set { active = value; }
115 public Socket Client {
116 get { return client; }
117 set {
118 client = value;
119 stream = null;
123 public int Available {
124 get { return client.Available; }
127 public bool Connected {
128 get { return client.Connected; }
131 public bool ExclusiveAddressUse {
132 get {
133 return(client.ExclusiveAddressUse);
135 set {
136 client.ExclusiveAddressUse = value;
140 public LingerOption LingerState {
141 get {
142 if ((values & Properties.LingerState) != 0)
143 return linger_state;
145 return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
146 SocketOptionName.Linger);
148 set {
149 if (!client.Connected) {
150 linger_state = value;
151 values |= Properties.LingerState;
152 return;
154 client.SetSocketOption(
155 SocketOptionLevel.Socket,
156 SocketOptionName.Linger, value);
160 public bool NoDelay {
161 get {
162 if ((values & Properties.NoDelay) != 0)
163 return no_delay;
165 return (bool)client.GetSocketOption(
166 SocketOptionLevel.Tcp,
167 SocketOptionName.NoDelay);
169 set {
170 if (!client.Connected) {
171 no_delay = value;
172 values |= Properties.NoDelay;
173 return;
175 client.SetSocketOption(
176 SocketOptionLevel.Tcp,
177 SocketOptionName.NoDelay, value ? 1 : 0);
181 public int ReceiveBufferSize {
182 get {
183 if ((values & Properties.ReceiveBufferSize) != 0)
184 return recv_buffer_size;
186 return (int)client.GetSocketOption(
187 SocketOptionLevel.Socket,
188 SocketOptionName.ReceiveBuffer);
190 set {
191 if (!client.Connected) {
192 recv_buffer_size = value;
193 values |= Properties.ReceiveBufferSize;
194 return;
196 client.SetSocketOption(
197 SocketOptionLevel.Socket,
198 SocketOptionName.ReceiveBuffer, value);
202 public int ReceiveTimeout {
203 get {
204 if ((values & Properties.ReceiveTimeout) != 0)
205 return recv_timeout;
207 return (int)client.GetSocketOption(
208 SocketOptionLevel.Socket,
209 SocketOptionName.ReceiveTimeout);
211 set {
212 if (!client.Connected) {
213 recv_timeout = value;
214 values |= Properties.ReceiveTimeout;
215 return;
217 client.SetSocketOption(
218 SocketOptionLevel.Socket,
219 SocketOptionName.ReceiveTimeout, value);
223 public int SendBufferSize {
224 get {
225 if ((values & Properties.SendBufferSize) != 0)
226 return send_buffer_size;
228 return (int)client.GetSocketOption(
229 SocketOptionLevel.Socket,
230 SocketOptionName.SendBuffer);
232 set {
233 if (!client.Connected) {
234 send_buffer_size = value;
235 values |= Properties.SendBufferSize;
236 return;
238 client.SetSocketOption(
239 SocketOptionLevel.Socket,
240 SocketOptionName.SendBuffer, value);
244 public int SendTimeout {
245 get {
246 if ((values & Properties.SendTimeout) != 0)
247 return send_timeout;
249 return (int)client.GetSocketOption(
250 SocketOptionLevel.Socket,
251 SocketOptionName.SendTimeout);
253 set {
254 if (!client.Connected) {
255 send_timeout = value;
256 values |= Properties.SendTimeout;
257 return;
259 client.SetSocketOption(
260 SocketOptionLevel.Socket,
261 SocketOptionName.SendTimeout, value);
266 // methods
268 public void Close ()
270 Dispose ();
273 public void Connect (IPEndPoint remoteEP)
275 try {
276 client.Connect (remoteEP);
277 active = true;
278 } finally {
279 CheckDisposed ();
283 public void Connect (IPAddress address, int port)
285 Connect(new IPEndPoint(address, port));
288 void SetOptions ()
290 Properties props = values;
291 values = 0;
293 if ((props & Properties.LingerState) != 0)
294 LingerState = linger_state;
295 if ((props & Properties.NoDelay) != 0)
296 NoDelay = no_delay;
297 if ((props & Properties.ReceiveBufferSize) != 0)
298 ReceiveBufferSize = recv_buffer_size;
299 if ((props & Properties.ReceiveTimeout) != 0)
300 ReceiveTimeout = recv_timeout;
301 if ((props & Properties.SendBufferSize) != 0)
302 SendBufferSize = send_buffer_size;
303 if ((props & Properties.SendTimeout) != 0)
304 SendTimeout = send_timeout;
307 public void Connect (string hostname, int port)
309 IPAddress [] addresses = Dns.GetHostAddresses (hostname);
310 Connect (addresses, port);
313 public void Connect (IPAddress[] ipAddresses, int port)
315 CheckDisposed ();
317 if (ipAddresses == null) {
318 throw new ArgumentNullException ("ipAddresses");
321 for(int i = 0; i < ipAddresses.Length; i++) {
322 try {
323 IPAddress address = ipAddresses[i];
325 if (address.Equals (IPAddress.Any) ||
326 address.Equals (IPAddress.IPv6Any)) {
327 throw new SocketException ((int)SocketError.AddressNotAvailable);
330 Init (address.AddressFamily);
332 if (address.AddressFamily == AddressFamily.InterNetwork) {
333 client.Bind (new IPEndPoint (IPAddress.Any, 0));
334 } else if (address.AddressFamily == AddressFamily.InterNetworkV6) {
335 client.Bind (new IPEndPoint (IPAddress.IPv6Any, 0));
336 } else {
337 throw new NotSupportedException ("This method is only valid for sockets in the InterNetwork and InterNetworkV6 families");
340 Connect (new IPEndPoint (address, port));
342 if (values != 0) {
343 SetOptions ();
346 break;
347 } catch (Exception e) {
348 /* Reinitialise the socket so
349 * other properties still work
350 * (see no-arg constructor)
352 Init (AddressFamily.InterNetwork);
354 /* This is the last known
355 * address, so re-throw the
356 * exception
358 if (i == ipAddresses.Length - 1) {
359 throw e;
365 public void EndConnect (IAsyncResult asyncResult)
367 client.EndConnect (asyncResult);
370 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback requestCallback, object state)
372 return client.BeginConnect (address, port, requestCallback, state);
375 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
377 return client.BeginConnect (addresses, port, requestCallback, state);
380 public IAsyncResult BeginConnect (string host, int port, AsyncCallback requestCallback, object state)
382 return client.BeginConnect (host, port, requestCallback, state);
385 public void Dispose ()
387 Dispose (true);
388 GC.SuppressFinalize (this);
391 protected virtual void Dispose (bool disposing)
393 if (disposed)
394 return;
395 disposed = true;
397 if (disposing) {
398 // release managed resources
399 NetworkStream s = stream;
400 stream = null;
401 if (s != null) {
402 // This closes the socket as well, as the NetworkStream
403 // owns the socket.
404 s.Close();
405 active = false;
406 s = null;
407 } else if (client != null){
408 client.Close ();
409 client = null;
414 ~TcpClient ()
416 Dispose (false);
419 public NetworkStream GetStream()
421 try {
422 if (stream == null)
423 stream = new NetworkStream (client, true);
424 return stream;
426 finally { CheckDisposed (); }
429 public Task ConnectAsync (IPAddress address, int port)
431 return Task.Factory.FromAsync (BeginConnect, EndConnect, address, port, null);
434 public Task ConnectAsync (IPAddress[] addresses, int port)
436 return Task.Factory.FromAsync (BeginConnect, EndConnect, addresses, port, null);
439 public Task ConnectAsync (string host, int port)
441 return Task.Factory.FromAsync (BeginConnect, EndConnect, host, port, null);
443 private void CheckDisposed ()
445 if (disposed)
446 throw new ObjectDisposedException (GetType().FullName);