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.
37 using System
.Threading
.Tasks
;
39 namespace System
.Net
.Sockets
41 public class TcpClient
: IDisposable
{
42 enum Properties
: uint {
45 ReceiveBufferSize
= 4,
57 int recv_timeout
, send_timeout
;
58 int recv_buffer_size
, send_buffer_size
;
59 LingerOption linger_state
;
62 private void Init (AddressFamily family
)
71 client
= new Socket(family
, SocketType
.Stream
, ProtocolType
.Tcp
);
76 Init(AddressFamily
.InterNetwork
);
77 client
.Bind(new IPEndPoint(IPAddress
.Any
, 0));
80 internal TcpClient (Socket 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");
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; }
123 public int Available
{
124 get { return client.Available; }
127 public bool Connected
{
128 get { return client.Connected; }
131 public bool ExclusiveAddressUse
{
133 return(client
.ExclusiveAddressUse
);
136 client
.ExclusiveAddressUse
= value;
140 public LingerOption LingerState
{
142 if ((values
& Properties
.LingerState
) != 0)
145 return (LingerOption
) client
.GetSocketOption (SocketOptionLevel
.Socket
,
146 SocketOptionName
.Linger
);
149 if (!client
.Connected
) {
150 linger_state
= value;
151 values
|= Properties
.LingerState
;
154 client
.SetSocketOption(
155 SocketOptionLevel
.Socket
,
156 SocketOptionName
.Linger
, value);
160 public bool NoDelay
{
162 if ((values
& Properties
.NoDelay
) != 0)
165 return (bool)client
.GetSocketOption(
166 SocketOptionLevel
.Tcp
,
167 SocketOptionName
.NoDelay
);
170 if (!client
.Connected
) {
172 values
|= Properties
.NoDelay
;
175 client
.SetSocketOption(
176 SocketOptionLevel
.Tcp
,
177 SocketOptionName
.NoDelay
, value ? 1 : 0);
181 public int ReceiveBufferSize
{
183 if ((values
& Properties
.ReceiveBufferSize
) != 0)
184 return recv_buffer_size
;
186 return (int)client
.GetSocketOption(
187 SocketOptionLevel
.Socket
,
188 SocketOptionName
.ReceiveBuffer
);
191 if (!client
.Connected
) {
192 recv_buffer_size
= value;
193 values
|= Properties
.ReceiveBufferSize
;
196 client
.SetSocketOption(
197 SocketOptionLevel
.Socket
,
198 SocketOptionName
.ReceiveBuffer
, value);
202 public int ReceiveTimeout
{
204 if ((values
& Properties
.ReceiveTimeout
) != 0)
207 return (int)client
.GetSocketOption(
208 SocketOptionLevel
.Socket
,
209 SocketOptionName
.ReceiveTimeout
);
212 if (!client
.Connected
) {
213 recv_timeout
= value;
214 values
|= Properties
.ReceiveTimeout
;
217 client
.SetSocketOption(
218 SocketOptionLevel
.Socket
,
219 SocketOptionName
.ReceiveTimeout
, value);
223 public int SendBufferSize
{
225 if ((values
& Properties
.SendBufferSize
) != 0)
226 return send_buffer_size
;
228 return (int)client
.GetSocketOption(
229 SocketOptionLevel
.Socket
,
230 SocketOptionName
.SendBuffer
);
233 if (!client
.Connected
) {
234 send_buffer_size
= value;
235 values
|= Properties
.SendBufferSize
;
238 client
.SetSocketOption(
239 SocketOptionLevel
.Socket
,
240 SocketOptionName
.SendBuffer
, value);
244 public int SendTimeout
{
246 if ((values
& Properties
.SendTimeout
) != 0)
249 return (int)client
.GetSocketOption(
250 SocketOptionLevel
.Socket
,
251 SocketOptionName
.SendTimeout
);
254 if (!client
.Connected
) {
255 send_timeout
= value;
256 values
|= Properties
.SendTimeout
;
259 client
.SetSocketOption(
260 SocketOptionLevel
.Socket
,
261 SocketOptionName
.SendTimeout
, value);
273 public void Connect (IPEndPoint remoteEP
)
276 client
.Connect (remoteEP
);
283 public void Connect (IPAddress address
, int port
)
285 Connect(new IPEndPoint(address
, port
));
290 Properties props
= values
;
293 if ((props
& Properties
.LingerState
) != 0)
294 LingerState
= linger_state
;
295 if ((props
& Properties
.NoDelay
) != 0)
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
)
317 if (ipAddresses
== null) {
318 throw new ArgumentNullException ("ipAddresses");
321 for(int i
= 0; i
< ipAddresses
.Length
; i
++) {
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));
337 throw new NotSupportedException ("This method is only valid for sockets in the InterNetwork and InterNetworkV6 families");
340 Connect (new IPEndPoint (address
, port
));
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
358 if (i
== ipAddresses
.Length
- 1) {
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 ()
388 GC
.SuppressFinalize (this);
391 protected virtual void Dispose (bool disposing
)
398 // release managed resources
399 NetworkStream s
= stream
;
402 // This closes the socket as well, as the NetworkStream
407 } else if (client
!= null){
419 public NetworkStream
GetStream()
423 stream
= new NetworkStream (client
, true);
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 ()
446 throw new ObjectDisposedException (GetType().FullName
);