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)
56 throw new ArgumentException("Family must be InterNetwork or InterNetworkV6", "family");
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);
74 public UdpClient (IPEndPoint localEP)
77 throw new ArgumentNullException ("localEP");
79 this.family = localEP.AddressFamily;
85 public UdpClient (int port, AddressFamily family)
87 if (family != AddressFamily.InterNetwork &&
88 family != AddressFamily.InterNetworkV6) {
89 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
92 if (port < IPEndPoint.MinPort ||
93 port > IPEndPoint.MaxPort) {
94 throw new ArgumentOutOfRangeException ("port");
99 IPEndPoint localEP = new IPEndPoint (IPAddress.Any, port);
100 InitSocket (localEP);
104 public UdpClient (string hostname, int port)
106 if (hostname == null)
107 throw new ArgumentNullException ("hostname");
109 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
110 throw new ArgumentOutOfRangeException ("port");
113 Connect (hostname, port);
116 private void InitSocket (EndPoint localEP)
123 socket = new Socket (family, SocketType.Dgram, ProtocolType.Udp);
126 socket.Bind (localEP);
129 #endregion // Constructors
130 #region Public methods
134 ((IDisposable) this).Dispose ();
139 void DoConnect (IPEndPoint endPoint)
141 /* Catch EACCES and turn on SO_BROADCAST then,
142 * as UDP sockets don't have it set by default
145 socket.Connect (endPoint);
146 } catch (SocketException ex) {
147 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
148 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
150 socket.Connect (endPoint);
157 public void Connect (IPEndPoint endPoint)
160 if (endPoint == null)
161 throw new ArgumentNullException ("endPoint");
163 DoConnect (endPoint);
167 public void Connect (IPAddress addr, int port)
170 throw new ArgumentNullException ("addr");
172 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
173 throw new ArgumentOutOfRangeException ("port");
176 Connect (new IPEndPoint (addr, port));
179 public void Connect (string hostname, int port)
181 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
182 throw new ArgumentOutOfRangeException ("port");
184 IPAddress[] addresses = Dns.GetHostAddresses (hostname);
185 for(int i=0; i<addresses.Length; i++) {
187 this.family = addresses[i].AddressFamily;
188 Connect (new IPEndPoint (addresses[i], port));
190 } catch(Exception e) {
191 if(i == addresses.Length - 1){
196 /// This is the last entry, re-throw the exception
203 #region Multicast methods
204 public void DropMulticastGroup (IPAddress multicastAddr)
207 if (multicastAddr == null)
208 throw new ArgumentNullException ("multicastAddr");
210 if(family == AddressFamily.InterNetwork)
211 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DropMembership,
212 new MulticastOption (multicastAddr));
215 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership,
216 new IPv6MulticastOption (multicastAddr));
221 public void DropMulticastGroup (IPAddress multicastAddr,
226 /* LAMESPEC: exceptions haven't been specified
229 if (multicastAddr == null) {
230 throw new ArgumentNullException ("multicastAddr");
233 /* Does this overload only apply to IPv6?
234 * Only the IPv6MulticastOption has an
235 * ifindex-using constructor. The MS docs
238 if (family == AddressFamily.InterNetworkV6) {
239 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership, new IPv6MulticastOption (multicastAddr, ifindex));
244 public void JoinMulticastGroup (IPAddress multicastAddr)
248 if(family == AddressFamily.InterNetwork)
249 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership,
250 new MulticastOption (multicastAddr));
253 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership,
254 new IPv6MulticastOption (multicastAddr));
259 public void JoinMulticastGroup (int ifindex,
260 IPAddress multicastAddr)
264 /* Does this overload only apply to IPv6?
265 * Only the IPv6MulticastOption has an
266 * ifindex-using constructor. The MS docs
269 if (family == AddressFamily.InterNetworkV6) {
270 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption (multicastAddr, ifindex));
275 public void JoinMulticastGroup (IPAddress multicastAddr, int timeToLive)
278 JoinMulticastGroup (multicastAddr);
279 if (timeToLive < 0 || timeToLive > 255)
280 throw new ArgumentOutOfRangeException ("timeToLive");
282 if(family == AddressFamily.InterNetwork)
283 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,
287 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive,
293 public void JoinMulticastGroup (IPAddress multicastAddr,
294 IPAddress localAddress)
298 if (family == AddressFamily.InterNetwork) {
299 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption (multicastAddr, localAddress));
300 } else if (family == AddressFamily.InterNetworkV6) {
301 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new MulticastOption (multicastAddr, localAddress));
308 public byte [] Receive (ref IPEndPoint remoteEP)
312 byte [] recBuffer = new byte [65536]; // Max. size
313 EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);
314 int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);
315 if (dataRead < recBuffer.Length)
316 recBuffer = CutArray (recBuffer, dataRead);
318 remoteEP = (IPEndPoint) endPoint;
322 int DoSend (byte[] dgram, int bytes, IPEndPoint endPoint)
324 /* Catch EACCES and turn on SO_BROADCAST then,
325 * as UDP sockets don't have it set by default
328 if (endPoint == null) {
329 return(socket.Send (dgram, 0, bytes,
332 return(socket.SendTo (dgram, 0, bytes,
336 } catch (SocketException ex) {
337 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
338 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
339 if (endPoint == null) {
340 return(socket.Send (dgram, 0, bytes, SocketFlags.None));
342 return(socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint));
350 public int Send (byte [] dgram, int bytes)
354 throw new ArgumentNullException ("dgram");
357 throw new InvalidOperationException ("Operation not allowed on " +
358 "non-connected sockets.");
360 return(DoSend (dgram, bytes, null));
363 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)
367 throw new ArgumentNullException ("dgram is null");
370 if (endPoint != null)
371 throw new InvalidOperationException ("Cannot send packets to an " +
372 "arbitrary host while connected.");
374 return(DoSend (dgram, bytes, null));
377 return(DoSend (dgram, bytes, endPoint));
380 public int Send (byte [] dgram, int bytes, string hostname, int port)
382 return Send (dgram, bytes,
383 new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port));
386 private byte [] CutArray (byte [] orig, int length)
388 byte [] newArray = new byte [length];
389 Buffer.BlockCopy (orig, 0, newArray, 0, length);
396 IAsyncResult DoBeginSend (byte[] datagram, int bytes,
398 AsyncCallback requestCallback,
401 /* Catch EACCES and turn on SO_BROADCAST then,
402 * as UDP sockets don't have it set by default
405 if (endPoint == null) {
406 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
408 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
410 } catch (SocketException ex) {
411 if (ex.ErrorCode == (int)SocketError.AccessDenied) {
412 socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
413 if (endPoint == null) {
414 return(socket.BeginSend (datagram, 0, bytes, SocketFlags.None, requestCallback, state));
416 return(socket.BeginSendTo (datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state));
424 public IAsyncResult BeginSend (byte[] datagram, int bytes,
425 AsyncCallback requestCallback,
428 return(BeginSend (datagram, bytes, null,
429 requestCallback, state));
432 public IAsyncResult BeginSend (byte[] datagram, int bytes,
434 AsyncCallback requestCallback,
439 if (datagram == null) {
440 throw new ArgumentNullException ("datagram");
443 return(DoBeginSend (datagram, bytes, endPoint,
444 requestCallback, state));
447 public IAsyncResult BeginSend (byte[] datagram, int bytes,
448 string hostname, int port,
449 AsyncCallback requestCallback,
452 return(BeginSend (datagram, bytes, new IPEndPoint (Dns.GetHostAddresses (hostname) [0], port), requestCallback, state));
455 public int EndSend (IAsyncResult asyncResult)
459 if (asyncResult == null) {
460 throw new ArgumentNullException ("asyncResult is a null reference");
463 return(socket.EndSend (asyncResult));
466 public IAsyncResult BeginReceive (AsyncCallback callback,
471 recvbuffer = new byte[8192];
475 if (family == AddressFamily.InterNetwork) {
476 ep = new IPEndPoint (IPAddress.Any, 0);
478 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
481 return(socket.BeginReceiveFrom (recvbuffer, 0, 8192,
487 public byte[] EndReceive (IAsyncResult asyncResult,
488 ref IPEndPoint remoteEP)
492 if (asyncResult == null) {
493 throw new ArgumentNullException ("asyncResult is a null reference");
498 if (family == AddressFamily.InterNetwork) {
499 ep = new IPEndPoint (IPAddress.Any, 0);
501 ep = new IPEndPoint (IPAddress.IPv6Any, 0);
504 int bytes = socket.EndReceiveFrom (asyncResult,
506 remoteEP = (IPEndPoint)ep;
508 /* Need to copy into a new array here, because
509 * otherwise the returned array length is not
512 byte[] buf = new byte[bytes];
513 Array.Copy (recvbuffer, buf, bytes);
520 protected bool Active {
521 get { return active; }
522 set { active = value; }
531 get { return socket; }
532 set { socket = value; }
539 return(socket.Available);
544 [MonoNotSupported ("Not supported as Socket.DontFragment is not supported")]
546 public bool DontFragment
549 return(socket.DontFragment);
552 socket.DontFragment = value;
557 [MonoNotSupported ("Not supported as Socket.EnableBroadcast is not supported")]
559 public bool EnableBroadcast
562 return(socket.EnableBroadcast);
565 socket.EnableBroadcast = value;
570 [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
572 public bool ExclusiveAddressUse
575 return(socket.ExclusiveAddressUse);
578 socket.ExclusiveAddressUse = value;
583 [MonoNotSupported ("Not supported as Socket.MulticastLoopback is not supported")]
585 public bool MulticastLoopback
588 return(socket.MulticastLoopback);
591 socket.MulticastLoopback = value;
596 [MonoNotSupported ("Not supported as Socket.Ttl is not supported")]
611 void IDisposable.Dispose ()
614 GC.SuppressFinalize (this);
620 void Dispose (bool disposing)
639 private void CheckDisposed ()
642 throw new ObjectDisposedException (GetType().FullName);