[Cleanup] Removed TARGET_JVM
[mono-project.git] / mcs / class / System / System.Net.Sockets / UdpClient.cs
bloba8bc06de5a829509fe42caa6b0ecd4252c502f5d
1 //
2 // System.Net.Sockets.UdpClient.cs
3 //
4 // Author:
5 // Gonzalo Paniagua Javier <gonzalo@ximian.com>
6 // Sridhar Kulkarni (sridharkulkarni@gmail.com)
7 // Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright (C) Ximian, Inc. http://www.ximian.com
10 // Copyright 2011 Xamarin Inc.
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System;
35 using System.Net;
36 #if NET_4_5
37 using System.Threading.Tasks;
38 #endif
40 namespace System.Net.Sockets
42 public class UdpClient : IDisposable
44 private bool disposed = false;
45 private bool active = false;
46 private Socket socket;
47 private AddressFamily family = AddressFamily.InterNetwork;
48 private byte[] recvbuffer;
50 public UdpClient () : this(AddressFamily.InterNetwork)
54 public UdpClient(AddressFamily family)
56 if(family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
57 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
59 this.family = family;
60 InitSocket (null);
63 public UdpClient (int port)
65 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
66 throw new ArgumentOutOfRangeException ("port");
68 this.family = AddressFamily.InterNetwork;
70 IPEndPoint localEP = new IPEndPoint (IPAddress.Any, port);
71 InitSocket (localEP);
74 public UdpClient (IPEndPoint localEP)
76 if (localEP == null)
77 throw new ArgumentNullException ("localEP");
79 this.family = localEP.AddressFamily;
81 InitSocket (localEP);
84 public UdpClient (int port, AddressFamily family)
86 if (family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
87 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
89 if (port < IPEndPoint.MinPort ||
90 port > IPEndPoint.MaxPort) {
91 throw new ArgumentOutOfRangeException ("port");
94 this.family = family;
96 IPEndPoint localEP;
98 if (family == AddressFamily.InterNetwork)
99 localEP = new IPEndPoint (IPAddress.Any, port);
100 else
101 localEP = new IPEndPoint (IPAddress.IPv6Any, port);
102 InitSocket (localEP);
105 public UdpClient (string hostname, int port)
107 if (hostname == null)
108 throw new ArgumentNullException ("hostname");
110 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
111 throw new ArgumentOutOfRangeException ("port");
113 InitSocket (null);
114 Connect (hostname, port);
117 private void InitSocket (EndPoint localEP)
119 if(socket != null) {
120 socket.Close();
121 socket = null;
124 socket = new Socket (family, SocketType.Dgram, ProtocolType.Udp);
126 if (localEP != null)
127 socket.Bind (localEP);
130 #region Close
131 public void Close ()
133 ((IDisposable) this).Dispose ();
135 #endregion
136 #region Connect
138 void DoConnect (IPEndPoint endPoint)
140 /* Catch EACCES and turn on SO_BROADCAST then,
141 * as UDP sockets don't have it set by default
143 try {
144 socket.Connect (endPoint);
145 } catch (SocketException ex) {
146 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
147 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
149 socket.Connect (endPoint);
150 } else {
151 throw;
156 public void Connect (IPEndPoint endPoint)
158 CheckDisposed ();
159 if (endPoint == null)
160 throw new ArgumentNullException ("endPoint");
162 DoConnect (endPoint);
163 active = true;
166 public void Connect (IPAddress addr, int port)
168 if (addr == null)
169 throw new ArgumentNullException ("addr");
171 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
172 throw new ArgumentOutOfRangeException ("port");
175 Connect (new IPEndPoint (addr, port));
178 public void Connect (string hostname, int port)
180 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
181 throw new ArgumentOutOfRangeException ("port");
183 IPAddress[] addresses = Dns.GetHostAddresses (hostname);
184 for(int i=0; i<addresses.Length; i++) {
185 try {
186 this.family = addresses[i].AddressFamily;
187 Connect (new IPEndPoint (addresses[i], port));
188 break;
189 } catch(Exception e) {
190 if(i == addresses.Length - 1){
191 if(socket != null) {
192 socket.Close();
193 socket = null;
195 /// This is the last entry, re-throw the exception
196 throw e;
201 #endregion
202 #region Multicast methods
203 public void DropMulticastGroup (IPAddress multicastAddr)
205 CheckDisposed ();
206 if (multicastAddr == null)
207 throw new ArgumentNullException ("multicastAddr");
209 if(family == AddressFamily.InterNetwork)
210 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DropMembership,
211 new MulticastOption (multicastAddr));
212 else
213 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership,
214 new IPv6MulticastOption (multicastAddr));
217 public void DropMulticastGroup (IPAddress multicastAddr,
218 int ifindex)
220 CheckDisposed ();
222 /* LAMESPEC: exceptions haven't been specified
223 * for this overload.
225 if (multicastAddr == null) {
226 throw new ArgumentNullException ("multicastAddr");
229 /* Does this overload only apply to IPv6?
230 * Only the IPv6MulticastOption has an
231 * ifindex-using constructor. The MS docs
232 * don't say.
234 if (family == AddressFamily.InterNetworkV6) {
235 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership, new IPv6MulticastOption (multicastAddr, ifindex));
239 public void JoinMulticastGroup (IPAddress multicastAddr)
241 CheckDisposed ();
243 if (multicastAddr == null)
244 throw new ArgumentNullException ("multicastAddr");
246 if(family == AddressFamily.InterNetwork)
247 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership,
248 new MulticastOption (multicastAddr));
249 else
250 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership,
251 new IPv6MulticastOption (multicastAddr));
254 public void JoinMulticastGroup (int ifindex,
255 IPAddress multicastAddr)
257 CheckDisposed ();
259 if (multicastAddr == null)
260 throw new ArgumentNullException ("multicastAddr");
262 if (family == AddressFamily.InterNetworkV6)
263 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption (multicastAddr, ifindex));
264 else
265 throw new SocketException ((int) SocketError.OperationNotSupported);
268 public void JoinMulticastGroup (IPAddress multicastAddr, int timeToLive)
270 CheckDisposed ();
271 if (multicastAddr == null)
272 throw new ArgumentNullException ("multicastAddr");
273 if (timeToLive < 0 || timeToLive > 255)
274 throw new ArgumentOutOfRangeException ("timeToLive");
276 JoinMulticastGroup (multicastAddr);
277 if(family == AddressFamily.InterNetwork)
278 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,
279 timeToLive);
280 else
281 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive,
282 timeToLive);
285 public void JoinMulticastGroup (IPAddress multicastAddr,
286 IPAddress localAddress)
288 CheckDisposed ();
290 if (family == AddressFamily.InterNetwork)
291 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption (multicastAddr, localAddress));
292 else
293 throw new SocketException ((int) SocketError.OperationNotSupported);
296 #endregion
297 #region Data I/O
298 public byte [] Receive (ref IPEndPoint remoteEP)
300 CheckDisposed ();
302 byte [] recBuffer = new byte [65536]; // Max. size
303 EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);
304 int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);
305 if (dataRead < recBuffer.Length)
306 recBuffer = CutArray (recBuffer, dataRead);
308 remoteEP = (IPEndPoint) endPoint;
309 return recBuffer;
312 int DoSend (byte[] dgram, int bytes, IPEndPoint endPoint)
314 /* Catch EACCES and turn on SO_BROADCAST then,
315 * as UDP sockets don't have it set by default
317 try {
318 if (endPoint == null) {
319 return(socket.Send (dgram, 0, bytes,
320 SocketFlags.None));
321 } else {
322 return(socket.SendTo (dgram, 0, bytes,
323 SocketFlags.None,
324 endPoint));
326 } catch (SocketException ex) {
327 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
328 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
329 if (endPoint == null) {
330 return(socket.Send (dgram, 0, bytes, SocketFlags.None));
331 } else {
332 return(socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint));
334 } else {
335 throw;
340 public int Send (byte [] dgram, int bytes)
342 CheckDisposed ();
343 if (dgram == null)
344 throw new ArgumentNullException ("dgram");
346 if (!active)
347 throw new InvalidOperationException ("Operation not allowed on " +
348 "non-connected sockets.");
350 return(DoSend (dgram, bytes, null));
353 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)
355 CheckDisposed ();
356 if (dgram == null)
357 throw new ArgumentNullException ("dgram is null");
359 if (active) {
360 if (endPoint != null)
361 throw new InvalidOperationException ("Cannot send packets to an " +
362 "arbitrary host while connected.");
364 return(DoSend (dgram, bytes, null));
367 return(DoSend (dgram, bytes, endPoint));
370 public int Send (byte [] dgram, int bytes, string hostname, int port)
372 return Send (dgram, bytes,
373 new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port));
376 private byte [] CutArray (byte [] orig, int length)
378 byte [] newArray = new byte [length];
379 Buffer.BlockCopy (orig, 0, newArray, 0, length);
381 return newArray;
383 #endregion
385 IAsyncResult DoBeginSend (byte[] datagram, int bytes,
386 IPEndPoint endPoint,
387 AsyncCallback requestCallback,
388 object state)
390 /* Catch EACCES and turn on SO_BROADCAST then,
391 * as UDP sockets don't have it set by default
393 try {
394 if (endPoint == null) {
395 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
396 } else {
397 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
399 } catch (SocketException ex) {
400 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
401 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
402 if (endPoint == null) {
403 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
404 } else {
405 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
407 } else {
408 throw;
413 public IAsyncResult BeginSend (byte[] datagram, int bytes,
414 AsyncCallback requestCallback,
415 object state)
417 return(BeginSend (datagram, bytes, null,
418 requestCallback, state));
421 public IAsyncResult BeginSend (byte[] datagram, int bytes,
422 IPEndPoint endPoint,
423 AsyncCallback requestCallback,
424 object state)
426 CheckDisposed ();
428 if (datagram == null) {
429 throw new ArgumentNullException ("datagram");
432 return(DoBeginSend (datagram, bytes, endPoint,
433 requestCallback, state));
436 public IAsyncResult BeginSend (byte[] datagram, int bytes,
437 string hostname, int port,
438 AsyncCallback requestCallback,
439 object state)
441 return(BeginSend (datagram, bytes, new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port), requestCallback, state));
444 public int EndSend (IAsyncResult asyncResult)
446 CheckDisposed ();
448 if (asyncResult == null) {
449 throw new ArgumentNullException ("asyncResult is a null reference");
452 return(socket.EndSend (asyncResult));
455 public IAsyncResult BeginReceive (AsyncCallback requestCallback, object state)
457 CheckDisposed ();
459 recvbuffer = new byte[8192];
461 EndPoint ep;
463 if (family == AddressFamily.InterNetwork) {
464 ep = new IPEndPoint (IPAddress.Any, 0);
465 } else {
466 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
469 return(socket.BeginReceiveFrom (recvbuffer, 0, 8192,
470 SocketFlags.None,
471 ref ep,
472 requestCallback, state));
475 public byte[] EndReceive (IAsyncResult asyncResult, ref IPEndPoint remoteEP)
477 CheckDisposed ();
479 if (asyncResult == null) {
480 throw new ArgumentNullException ("asyncResult is a null reference");
483 EndPoint ep;
485 if (family == AddressFamily.InterNetwork) {
486 ep = new IPEndPoint (IPAddress.Any, 0);
487 } else {
488 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
491 int bytes = socket.EndReceiveFrom (asyncResult,
492 ref ep);
493 remoteEP = (IPEndPoint)ep;
495 /* Need to copy into a new array here, because
496 * otherwise the returned array length is not
497 * 'bytes'
499 byte[] buf = new byte[bytes];
500 Array.Copy (recvbuffer, buf, bytes);
502 return(buf);
505 #region Properties
506 protected bool Active {
507 get { return active; }
508 set { active = value; }
511 public Socket Client {
512 get { return socket; }
513 set { socket = value; }
516 public int Available
518 get {
519 return(socket.Available);
523 public bool DontFragment
525 get {
526 return(socket.DontFragment);
528 set {
529 socket.DontFragment = value;
533 public bool EnableBroadcast
535 get {
536 return(socket.EnableBroadcast);
538 set {
539 socket.EnableBroadcast = value;
543 public bool ExclusiveAddressUse
545 get {
546 return(socket.ExclusiveAddressUse);
548 set {
549 socket.ExclusiveAddressUse = value;
553 public bool MulticastLoopback
555 get {
556 return(socket.MulticastLoopback);
558 set {
559 socket.MulticastLoopback = value;
563 public short Ttl
565 get {
566 return(socket.Ttl);
568 set {
569 socket.Ttl = value;
573 #endregion
574 #region Disposing
575 void IDisposable.Dispose ()
577 Dispose (true);
578 GC.SuppressFinalize (this);
581 protected virtual void Dispose (bool disposing)
583 if (disposed)
584 return;
585 disposed = true;
587 if (disposing){
588 if (socket != null)
589 socket.Close ();
591 socket = null;
595 ~UdpClient ()
597 Dispose (false);
600 private void CheckDisposed ()
602 if (disposed)
603 throw new ObjectDisposedException (GetType().FullName);
605 #endregion
607 #if NET_4_5
609 public Task<UdpReceiveResult> ReceiveAsync ()
611 return Task<UdpReceiveResult>.Factory.FromAsync (BeginReceive, r => {
612 IPEndPoint remoteEndPoint = null;
613 return new UdpReceiveResult (EndReceive (r, ref remoteEndPoint), remoteEndPoint);
614 }, null);
617 public Task<int> SendAsync (byte[] datagram, int bytes)
619 return Task<int>.Factory.FromAsync (BeginSend, EndSend, datagram, bytes, null);
622 public Task<int> SendAsync (byte[] datagram, int bytes, IPEndPoint endPoint)
624 return Task<int>.Factory.FromAsync (BeginSend, EndSend, datagram, bytes, endPoint, null);
627 public Task<int> SendAsync (byte[] datagram, int bytes, string hostname, int port)
629 var t = Tuple.Create (datagram, bytes, hostname, port, this);
631 return Task<int>.Factory.FromAsync ((callback, state) => {
632 var d = (Tuple<byte[], int, string, int, UdpClient>) state;
633 return d.Item5.BeginSend (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
634 }, EndSend, t);
637 #endif