2004-04-28 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System / System.Net.Sockets / UdpClient.cs
1 //\r
2 // System.Net.Sockets.UdpClient.cs\r
3 //\r
4 // Author:\r
5 //    Gonzalo Paniagua Javier <gonzalo@ximian.com>\r
6 //\r
7 // Copyright (C) Ximian, Inc. http://www.ximian.com\r
8 //\r
9 \r
10 using System;\r
11 using System.Net;\r
12 \r
13 namespace System.Net.Sockets\r
14 {\r
15         public class UdpClient : IDisposable\r
16         {\r
17                 private bool disposed = false;\r
18                 private bool active = false;\r
19                 private Socket socket;\r
20                 private AddressFamily family = AddressFamily.InterNetwork;\r
21                 \r
22 #region Constructors\r
23                 public UdpClient () : this(AddressFamily.InterNetwork)\r
24                 {\r
25                 }\r
26 \r
27                 public UdpClient(AddressFamily family)\r
28                 {\r
29                         if(family != AddressFamily.InterNetwork && family != AddressFamily.InterNetwork)\r
30                                 throw new ArgumentException("family");\r
31 \r
32                         this.family = family;\r
33                         InitSocket (null);\r
34                 }\r
35 \r
36                 public UdpClient (int port)\r
37                 {\r
38                         if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)\r
39                                 throw new ArgumentOutOfRangeException ("port");\r
40 \r
41                         this.family = AddressFamily.InterNetwork;\r
42 \r
43                         IPEndPoint localEP = new IPEndPoint (IPAddress.Any, port);\r
44                         InitSocket (localEP);\r
45                 }\r
46 \r
47                 public UdpClient (IPEndPoint localEP)\r
48                 {\r
49                         if (localEP == null)\r
50                                 throw new ArgumentNullException ("localEP");\r
51 \r
52                         this.family = localEP.AddressFamily;\r
53 \r
54                         InitSocket (localEP);\r
55                 }\r
56 \r
57                 public UdpClient (string hostname, int port)\r
58                 {\r
59                         if (hostname == null)\r
60                                 throw new ArgumentNullException ("hostname");\r
61 \r
62                         if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)\r
63                                 throw new ArgumentOutOfRangeException ("port");\r
64 \r
65                         InitSocket (null);\r
66                         Connect (hostname, port);\r
67                 }\r
68 \r
69                 private void InitSocket (EndPoint localEP)\r
70                 {\r
71                         if(socket != null) {\r
72                                 socket.Close();\r
73                                 socket = null;\r
74                         }\r
75 \r
76                         socket = new Socket (family, SocketType.Dgram, ProtocolType.Udp);\r
77 \r
78                         if (localEP != null)\r
79                                 socket.Bind (localEP);\r
80                 }\r
81 \r
82 #endregion // Constructors\r
83 #region Public methods\r
84 #region Close\r
85                 public void Close ()\r
86                 {\r
87                         ((IDisposable) this).Dispose ();        \r
88                 }\r
89 #endregion\r
90 #region Connect\r
91                 public void Connect (IPEndPoint endPoint)\r
92                 {\r
93                         CheckDisposed ();\r
94                         if (endPoint == null)\r
95                                 throw new ArgumentNullException ("endPoint");\r
96 \r
97                         socket.Connect (endPoint);\r
98                         active = true;\r
99                 }\r
100 \r
101                 public void Connect (IPAddress addr, int port)\r
102                 {\r
103                         if (addr == null)\r
104                                 throw new ArgumentNullException ("addr");\r
105 \r
106                         if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)\r
107                                 throw new ArgumentOutOfRangeException ("port");\r
108 \r
109                         Connect (new IPEndPoint (addr, port));\r
110                 }\r
111 \r
112                 public void Connect (string hostname, int port)\r
113                 {\r
114                         if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)\r
115                                 throw new ArgumentOutOfRangeException ("port");\r
116 \r
117                         IPAddress[] addresses = Dns.Resolve (hostname).AddressList;\r
118                         for(int i=0; i<addresses.Length; i++) {\r
119                                 try {\r
120                                         this.family = addresses[i].AddressFamily;\r
121                                         Connect (new IPEndPoint (addresses[i], port));\r
122                                         break;\r
123                                 } catch(Exception e) {\r
124                                         if(i == addresses.Length - 1){\r
125                                                 if(socket != null) {\r
126                                                         socket.Close();\r
127                                                         socket = null;\r
128                                                 }\r
129 \r
130                                                 /// This is the last entry, re-throw the exception\r
131                                                 throw e;\r
132                                         }\r
133                                 }\r
134                         }\r
135                 }\r
136 #endregion\r
137                 #region Multicast methods\r
138                 public void DropMulticastGroup (IPAddress multicastAddr)\r
139                 {\r
140                         CheckDisposed ();\r
141                         if (multicastAddr == null)\r
142                                 throw new ArgumentNullException ("multicastAddr");\r
143 \r
144                         if(family == AddressFamily.InterNetwork)\r
145                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DropMembership,\r
146                                         new MulticastOption (multicastAddr));\r
147 #if NET_1_1\r
148                         else\r
149                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership,\r
150                                         new IPv6MulticastOption (multicastAddr));\r
151 #endif\r
152                 }\r
153 \r
154                 public void JoinMulticastGroup (IPAddress multicastAddr)\r
155                 {\r
156                         CheckDisposed ();\r
157 \r
158                         if(family == AddressFamily.InterNetwork)\r
159                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership,\r
160                                         new MulticastOption (multicastAddr));\r
161 #if NET_1_1\r
162                         else\r
163                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership,\r
164                                         new IPv6MulticastOption (multicastAddr));\r
165 #endif\r
166                 }\r
167 \r
168                 public void JoinMulticastGroup (IPAddress multicastAddr, int timeToLive)\r
169                 {\r
170                         CheckDisposed ();\r
171                         JoinMulticastGroup (multicastAddr);\r
172                         if (timeToLive < 0 || timeToLive > 255)\r
173                                 throw new ArgumentOutOfRangeException ("timeToLive");\r
174 \r
175                         if(family == AddressFamily.InterNetwork)\r
176                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,\r
177                                         timeToLive);\r
178 #if NET_1_1\r
179                         else\r
180                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive,\r
181                                         timeToLive);\r
182 #endif\r
183                 }\r
184                 #endregion\r
185 #region Data I/O\r
186                 public byte [] Receive (ref IPEndPoint remoteEP)\r
187                 {\r
188                         CheckDisposed ();\r
189 \r
190                         // Bug 45633: the spec states that we should block until a datagram arrives:\r
191                         // remove the 512 hardcoded value.\r
192 \r
193                         // Block until we get it.\r
194                         socket.Poll (-1, SelectMode.SelectRead);\r
195                         \r
196                         byte [] recBuffer;\r
197                         int available = socket.Available;\r
198 \r
199                         recBuffer = new byte [available];\r
200                         EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);\r
201                         int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);\r
202                         if (dataRead < recBuffer.Length)\r
203                                 recBuffer = CutArray (recBuffer, dataRead);\r
204 \r
205                         remoteEP = (IPEndPoint) endPoint;\r
206                         return recBuffer;\r
207                 }\r
208 \r
209                 public int Send (byte [] dgram, int bytes)\r
210                 {\r
211                         CheckDisposed ();\r
212                         if (dgram == null)\r
213                                 throw new ArgumentNullException ("dgram");\r
214 \r
215                         if (!active)\r
216                                 throw new InvalidOperationException ("Operation not allowed on " + \r
217                                                                      "non-connected sockets.");\r
218 \r
219                         return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
220                 }\r
221 \r
222                 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)\r
223                 {\r
224                         CheckDisposed ();\r
225                         if (dgram == null)\r
226                                 throw new ArgumentNullException ("dgram is null");\r
227                         \r
228                         if (active) {\r
229                                 if (endPoint != null)\r
230                                         throw new InvalidOperationException ("Cannot send packets to an " +\r
231                                                                              "arbitrary host while connected.");\r
232 \r
233                                 return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
234                         }\r
235                         \r
236                         return socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint);\r
237                 }\r
238 \r
239                 public int Send (byte [] dgram, int bytes, string hostname, int port)\r
240                 {\r
241                         return Send (dgram, bytes, \r
242                                      new IPEndPoint (Dns.Resolve (hostname).AddressList [0], port));\r
243                 }\r
244 \r
245                 private byte [] CutArray (byte [] orig, int length)\r
246                 {\r
247                         byte [] newArray = new byte [length];\r
248                         Buffer.BlockCopy (orig, 0, newArray, 0, length);\r
249 \r
250                         return newArray;\r
251                 }\r
252 #endregion\r
253 #region Properties\r
254                 protected bool Active {\r
255                         get { return active; }\r
256                         set { active = value; }\r
257                 }\r
258 \r
259                 protected Socket Client {\r
260                         get { return socket; }\r
261                         set { socket = value; }\r
262                 }\r
263 #endregion\r
264 #region Disposing\r
265                 void IDisposable.Dispose ()\r
266                 {\r
267                         Dispose (true);\r
268                         GC.SuppressFinalize (this);\r
269                 }\r
270 \r
271                 void Dispose (bool disposing)\r
272                 {\r
273                         if (disposed)\r
274                                 return;\r
275                         disposed = true;\r
276 \r
277                         if (disposing){\r
278                                 if (socket != null)\r
279                                         socket.Close ();\r
280 \r
281                                 socket = null;\r
282                         }\r
283                 }\r
284                 \r
285                 ~UdpClient ()\r
286                 {\r
287                         Dispose (false);\r
288                 }\r
289                 \r
290                 private void CheckDisposed ()\r
291                 {\r
292                         if (disposed)\r
293                                 throw new ObjectDisposedException (GetType().FullName);\r
294                 }               \r
295 #endregion\r
296 #endregion\r
297         }\r
298 }\r
299 \r