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)
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
38 using System.Threading.Tasks;
41 namespace System.Net.Sockets
43 public class TcpClient : IDisposable {
44 enum Properties : uint {
47 ReceiveBufferSize = 4,
59 int recv_timeout, send_timeout;
60 int recv_buffer_size, send_buffer_size;
61 LingerOption linger_state;
64 private void Init (AddressFamily family)
73 client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
78 Init(AddressFamily.InterNetwork);
79 client.Bind(new IPEndPoint(IPAddress.Any, 0));
82 internal TcpClient (Socket s)
87 public TcpClient (AddressFamily family)
89 if (family != AddressFamily.InterNetwork &&
90 family != AddressFamily.InterNetworkV6) {
91 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
95 IPAddress any = IPAddress.Any;
96 if (family == AddressFamily.InterNetworkV6)
97 any = IPAddress.IPv6Any;
98 client.Bind (new IPEndPoint (any, 0));
101 public TcpClient (IPEndPoint localEP)
103 Init (localEP.AddressFamily);
104 client.Bind (localEP);
107 public TcpClient (string hostname, int port)
109 Connect(hostname, port);
112 protected bool Active {
113 get { return active; }
114 set { active = value; }
117 public Socket Client {
118 get { return client; }
125 public int Available {
126 get { return client.Available; }
129 public bool Connected {
130 get { return client.Connected; }
134 [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
136 public bool ExclusiveAddressUse {
138 return(client.ExclusiveAddressUse);
141 client.ExclusiveAddressUse = value;
145 public LingerOption LingerState {
147 if ((values & Properties.LingerState) != 0)
150 return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
151 SocketOptionName.Linger);
154 if (!client.Connected) {
155 linger_state = value;
156 values |= Properties.LingerState;
159 client.SetSocketOption(
160 SocketOptionLevel.Socket,
161 SocketOptionName.Linger, value);
165 public bool NoDelay {
167 if ((values & Properties.NoDelay) != 0)
170 return (bool)client.GetSocketOption(
171 SocketOptionLevel.Tcp,
172 SocketOptionName.NoDelay);
175 if (!client.Connected) {
177 values |= Properties.NoDelay;
180 client.SetSocketOption(
181 SocketOptionLevel.Tcp,
182 SocketOptionName.NoDelay, value ? 1 : 0);
186 public int ReceiveBufferSize {
188 if ((values & Properties.ReceiveBufferSize) != 0)
189 return recv_buffer_size;
191 return (int)client.GetSocketOption(
192 SocketOptionLevel.Socket,
193 SocketOptionName.ReceiveBuffer);
196 if (!client.Connected) {
197 recv_buffer_size = value;
198 values |= Properties.ReceiveBufferSize;
201 client.SetSocketOption(
202 SocketOptionLevel.Socket,
203 SocketOptionName.ReceiveBuffer, value);
207 public int ReceiveTimeout {
209 if ((values & Properties.ReceiveTimeout) != 0)
212 return (int)client.GetSocketOption(
213 SocketOptionLevel.Socket,
214 SocketOptionName.ReceiveTimeout);
217 if (!client.Connected) {
218 recv_timeout = value;
219 values |= Properties.ReceiveTimeout;
222 client.SetSocketOption(
223 SocketOptionLevel.Socket,
224 SocketOptionName.ReceiveTimeout, value);
228 public int SendBufferSize {
230 if ((values & Properties.SendBufferSize) != 0)
231 return send_buffer_size;
233 return (int)client.GetSocketOption(
234 SocketOptionLevel.Socket,
235 SocketOptionName.SendBuffer);
238 if (!client.Connected) {
239 send_buffer_size = value;
240 values |= Properties.SendBufferSize;
243 client.SetSocketOption(
244 SocketOptionLevel.Socket,
245 SocketOptionName.SendBuffer, value);
249 public int SendTimeout {
251 if ((values & Properties.SendTimeout) != 0)
254 return (int)client.GetSocketOption(
255 SocketOptionLevel.Socket,
256 SocketOptionName.SendTimeout);
259 if (!client.Connected) {
260 send_timeout = value;
261 values |= Properties.SendTimeout;
264 client.SetSocketOption(
265 SocketOptionLevel.Socket,
266 SocketOptionName.SendTimeout, value);
275 ((IDisposable) this).Dispose ();
278 public void Connect (IPEndPoint remoteEP)
281 client.Connect (remoteEP);
288 public void Connect (IPAddress address, int port)
290 Connect(new IPEndPoint(address, port));
295 Properties props = values;
298 if ((props & Properties.LingerState) != 0)
299 LingerState = linger_state;
300 if ((props & Properties.NoDelay) != 0)
302 if ((props & Properties.ReceiveBufferSize) != 0)
303 ReceiveBufferSize = recv_buffer_size;
304 if ((props & Properties.ReceiveTimeout) != 0)
305 ReceiveTimeout = recv_timeout;
306 if ((props & Properties.SendBufferSize) != 0)
307 SendBufferSize = send_buffer_size;
308 if ((props & Properties.SendTimeout) != 0)
309 SendTimeout = send_timeout;
312 public void Connect (string hostname, int port)
314 IPAddress [] addresses = Dns.GetHostAddresses (hostname);
315 Connect (addresses, port);
318 public void Connect (IPAddress[] ipAddresses, int port)
322 if (ipAddresses == null) {
323 throw new ArgumentNullException ("ipAddresses");
326 for(int i = 0; i < ipAddresses.Length; i++) {
328 IPAddress address = ipAddresses[i];
330 if (address.Equals (IPAddress.Any) ||
331 address.Equals (IPAddress.IPv6Any)) {
332 throw new SocketException ((int)SocketError.AddressNotAvailable);
335 Init (address.AddressFamily);
337 if (address.AddressFamily == AddressFamily.InterNetwork) {
338 client.Bind (new IPEndPoint (IPAddress.Any, 0));
339 } else if (address.AddressFamily == AddressFamily.InterNetworkV6) {
340 client.Bind (new IPEndPoint (IPAddress.IPv6Any, 0));
342 throw new NotSupportedException ("This method is only valid for sockets in the InterNetwork and InterNetworkV6 families");
345 Connect (new IPEndPoint (address, port));
352 } catch (Exception e) {
353 /* Reinitialise the socket so
354 * other properties still work
355 * (see no-arg constructor)
357 Init (AddressFamily.InterNetwork);
359 /* This is the last known
360 * address, so re-throw the
363 if (i == ipAddresses.Length - 1) {
370 public void EndConnect (IAsyncResult asyncResult)
372 client.EndConnect (asyncResult);
376 [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
378 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback requestCallback, object state)
380 return client.BeginConnect (address, port, requestCallback, state);
384 [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
386 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
388 return client.BeginConnect (addresses, port, requestCallback, state);
392 [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
394 public IAsyncResult BeginConnect (string host, int port, AsyncCallback requestCallback, object state)
396 return client.BeginConnect (host, port, requestCallback, state);
399 void IDisposable.Dispose ()
402 GC.SuppressFinalize (this);
405 protected virtual void Dispose (bool disposing)
412 // release managed resources
413 NetworkStream s = stream;
416 // This closes the socket as well, as the NetworkStream
421 } else if (client != null){
433 public NetworkStream GetStream()
437 stream = new NetworkStream (client, true);
440 finally { CheckDisposed (); }
444 public Task ConnectAsync (IPAddress address, int port)
446 return Task.Factory.FromAsync (BeginConnect, EndConnect, address, port, null);
449 public Task ConnectAsync (IPAddress[] addresses, int port)
451 return Task.Factory.FromAsync (BeginConnect, EndConnect, addresses, port, null);
454 public Task ConnectAsync (string host, int port)
456 return Task.Factory.FromAsync (BeginConnect, EndConnect, host, port, null);
459 private void CheckDisposed ()
462 throw new ObjectDisposedException (GetType().FullName);