2 // System.Net.Sockets.UdpClient.cs
5 // Gonzalo Paniagua Javier <gonzalo@ximian.com>
6 // Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 // Copyright (C) Ximian, Inc. http://www.ximian.com
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 namespace System.Net.Sockets
37 public class UdpClient : IDisposable
39 private bool disposed = false;
40 private bool active = false;
41 private Socket socket;
42 private AddressFamily family = AddressFamily.InterNetwork;
44 private byte[] recvbuffer;
48 public UdpClient () : this(AddressFamily.InterNetwork)
53 public UdpClient(AddressFamily family)
55 if(family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
57 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
59 throw new ArgumentException ("family");
67 public UdpClient (int port)
69 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
70 throw new ArgumentOutOfRangeException ("port");
72 this.family = AddressFamily.InterNetwork;
74 IPEndPoint localEP = new IPEndPoint (IPAddress.Any, port);
78 public UdpClient (IPEndPoint localEP)
81 throw new ArgumentNullException ("localEP");
83 this.family = localEP.AddressFamily;
89 public UdpClient (int port, AddressFamily family)
91 if (family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
93 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
95 throw new ArgumentException ("family");
98 if (port < IPEndPoint.MinPort ||
99 port > IPEndPoint.MaxPort) {
100 throw new ArgumentOutOfRangeException ("port");
103 this.family = family;
107 if (family == AddressFamily.InterNetwork)
108 localEP = new IPEndPoint (IPAddress.Any, port);
110 localEP = new IPEndPoint (IPAddress.IPv6Any, port);
111 InitSocket (localEP);
115 public UdpClient (string hostname, int port)
117 if (hostname == null)
118 throw new ArgumentNullException ("hostname");
120 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
121 throw new ArgumentOutOfRangeException ("port");
124 Connect (hostname, port);
127 private void InitSocket (EndPoint localEP)
134 socket = new Socket (family, SocketType.Dgram, ProtocolType.Udp);
137 socket.Bind (localEP);
140 #endregion // Constructors
141 #region Public methods
145 ((IDisposable) this).Dispose ();
150 void DoConnect (IPEndPoint endPoint)
152 /* Catch EACCES and turn on SO_BROADCAST then,
153 * as UDP sockets don't have it set by default
156 socket.Connect (endPoint);
157 } catch (SocketException ex) {
158 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
159 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
161 socket.Connect (endPoint);
168 public void Connect (IPEndPoint endPoint)
171 if (endPoint == null)
172 throw new ArgumentNullException ("endPoint");
174 DoConnect (endPoint);
178 public void Connect (IPAddress addr, int port)
181 throw new ArgumentNullException ("addr");
183 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
184 throw new ArgumentOutOfRangeException ("port");
187 Connect (new IPEndPoint (addr, port));
190 public void Connect (string hostname, int port)
192 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
193 throw new ArgumentOutOfRangeException ("port");
195 IPAddress[] addresses = Dns.GetHostAddresses (hostname);
196 for(int i=0; i<addresses.Length; i++) {
198 this.family = addresses[i].AddressFamily;
199 Connect (new IPEndPoint (addresses[i], port));
201 } catch(Exception e) {
202 if(i == addresses.Length - 1){
207 /// This is the last entry, re-throw the exception
214 #region Multicast methods
215 public void DropMulticastGroup (IPAddress multicastAddr)
218 if (multicastAddr == null)
219 throw new ArgumentNullException ("multicastAddr");
221 if(family == AddressFamily.InterNetwork)
222 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DropMembership,
223 new MulticastOption (multicastAddr));
226 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership,
227 new IPv6MulticastOption (multicastAddr));
232 public void DropMulticastGroup (IPAddress multicastAddr,
237 /* LAMESPEC: exceptions haven't been specified
240 if (multicastAddr == null) {
241 throw new ArgumentNullException ("multicastAddr");
244 /* Does this overload only apply to IPv6?
245 * Only the IPv6MulticastOption has an
246 * ifindex-using constructor. The MS docs
249 if (family == AddressFamily.InterNetworkV6) {
250 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership, new IPv6MulticastOption (multicastAddr, ifindex));
255 public void JoinMulticastGroup (IPAddress multicastAddr)
259 if (multicastAddr == null)
261 throw new ArgumentNullException ("multicastAddr");
263 throw new NullReferenceException ();
266 if(family == AddressFamily.InterNetwork)
267 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership,
268 new MulticastOption (multicastAddr));
271 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership,
272 new IPv6MulticastOption (multicastAddr));
277 public void JoinMulticastGroup (int ifindex,
278 IPAddress multicastAddr)
282 if (multicastAddr == null)
283 throw new ArgumentNullException ("multicastAddr");
285 if (family == AddressFamily.InterNetworkV6)
286 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption (multicastAddr, ifindex));
288 throw new SocketException ((int) SocketError.OperationNotSupported);
292 public void JoinMulticastGroup (IPAddress multicastAddr, int timeToLive)
295 if (multicastAddr == null)
296 throw new ArgumentNullException ("multicastAddr");
297 if (timeToLive < 0 || timeToLive > 255)
298 throw new ArgumentOutOfRangeException ("timeToLive");
300 JoinMulticastGroup (multicastAddr);
301 if(family == AddressFamily.InterNetwork)
302 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,
306 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive,
312 public void JoinMulticastGroup (IPAddress multicastAddr,
313 IPAddress localAddress)
317 if (family == AddressFamily.InterNetwork)
318 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption (multicastAddr, localAddress));
320 throw new SocketException ((int) SocketError.OperationNotSupported);
326 public byte [] Receive (ref IPEndPoint remoteEP)
330 byte [] recBuffer = new byte [65536]; // Max. size
331 EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);
332 int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);
333 if (dataRead < recBuffer.Length)
334 recBuffer = CutArray (recBuffer, dataRead);
336 remoteEP = (IPEndPoint) endPoint;
340 int DoSend (byte[] dgram, int bytes, IPEndPoint endPoint)
342 /* Catch EACCES and turn on SO_BROADCAST then,
343 * as UDP sockets don't have it set by default
346 if (endPoint == null) {
347 return(socket.Send (dgram, 0, bytes,
350 return(socket.SendTo (dgram, 0, bytes,
354 } catch (SocketException ex) {
355 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
356 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
357 if (endPoint == null) {
358 return(socket.Send (dgram, 0, bytes, SocketFlags.None));
360 return(socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint));
368 public int Send (byte [] dgram, int bytes)
372 throw new ArgumentNullException ("dgram");
375 throw new InvalidOperationException ("Operation not allowed on " +
376 "non-connected sockets.");
378 return(DoSend (dgram, bytes, null));
381 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)
385 throw new ArgumentNullException ("dgram is null");
388 if (endPoint != null)
389 throw new InvalidOperationException ("Cannot send packets to an " +
390 "arbitrary host while connected.");
392 return(DoSend (dgram, bytes, null));
395 return(DoSend (dgram, bytes, endPoint));
398 public int Send (byte [] dgram, int bytes, string hostname, int port)
400 return Send (dgram, bytes,
401 new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port));
404 private byte [] CutArray (byte [] orig, int length)
406 byte [] newArray = new byte [length];
407 Buffer.BlockCopy (orig, 0, newArray, 0, length);
414 IAsyncResult DoBeginSend (byte[] datagram, int bytes,
416 AsyncCallback requestCallback,
419 /* Catch EACCES and turn on SO_BROADCAST then,
420 * as UDP sockets don't have it set by default
423 if (endPoint == null) {
424 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
426 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
428 } catch (SocketException ex) {
429 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
430 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
431 if (endPoint == null) {
432 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
434 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
442 public IAsyncResult BeginSend (byte[] datagram, int bytes,
443 AsyncCallback requestCallback,
446 return(BeginSend (datagram, bytes, null,
447 requestCallback, state));
450 public IAsyncResult BeginSend (byte[] datagram, int bytes,
452 AsyncCallback requestCallback,
457 if (datagram == null) {
458 throw new ArgumentNullException ("datagram");
461 return(DoBeginSend (datagram, bytes, endPoint,
462 requestCallback, state));
465 public IAsyncResult BeginSend (byte[] datagram, int bytes,
466 string hostname, int port,
467 AsyncCallback requestCallback,
470 return(BeginSend (datagram, bytes, new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port), requestCallback, state));
473 public int EndSend (IAsyncResult asyncResult)
477 if (asyncResult == null) {
478 throw new ArgumentNullException ("asyncResult is a null reference");
481 return(socket.EndSend (asyncResult));
484 public IAsyncResult BeginReceive (AsyncCallback callback,
489 recvbuffer = new byte[8192];
493 if (family == AddressFamily.InterNetwork) {
494 ep = new IPEndPoint (IPAddress.Any, 0);
496 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
499 return(socket.BeginReceiveFrom (recvbuffer, 0, 8192,
505 public byte[] EndReceive (IAsyncResult asyncResult,
506 ref IPEndPoint remoteEP)
510 if (asyncResult == null) {
511 throw new ArgumentNullException ("asyncResult is a null reference");
516 if (family == AddressFamily.InterNetwork) {
517 ep = new IPEndPoint (IPAddress.Any, 0);
519 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
522 int bytes = socket.EndReceiveFrom (asyncResult,
524 remoteEP = (IPEndPoint)ep;
526 /* Need to copy into a new array here, because
527 * otherwise the returned array length is not
530 byte[] buf = new byte[bytes];
531 Array.Copy (recvbuffer, buf, bytes);
538 protected bool Active {
539 get { return active; }
540 set { active = value; }
549 get { return socket; }
550 set { socket = value; }
557 return(socket.Available);
562 [MonoNotSupported ("Not supported as Socket.DontFragment is not supported")]
564 public bool DontFragment
567 return(socket.DontFragment);
570 socket.DontFragment = value;
575 [MonoNotSupported ("Not supported as Socket.EnableBroadcast is not supported")]
577 public bool EnableBroadcast
580 return(socket.EnableBroadcast);
583 socket.EnableBroadcast = value;
588 [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
590 public bool ExclusiveAddressUse
593 return(socket.ExclusiveAddressUse);
596 socket.ExclusiveAddressUse = value;
601 [MonoNotSupported ("Not supported as Socket.MulticastLoopback is not supported")]
603 public bool MulticastLoopback
606 return(socket.MulticastLoopback);
609 socket.MulticastLoopback = value;
614 [MonoNotSupported ("Not supported as Socket.Ttl is not supported")]
629 void IDisposable.Dispose ()
632 GC.SuppressFinalize (this);
638 void Dispose (bool disposing)
657 private void CheckDisposed ()
660 throw new ObjectDisposedException (GetType().FullName);