2003-08-10 Miguel de Icaza <miguel@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                                         Console.WriteLine("Trying: {0}, Family: {1}", addresses[i], addresses[i].AddressFamily);\r
121 \r
122                                         this.family = addresses[i].AddressFamily;\r
123                                         Connect (new IPEndPoint (addresses[i], port));\r
124 \r
125                                         Console.WriteLine("Connected: {0}, Family: {1}", addresses[i], family);\r
126                                         break;\r
127                                 }\r
128                                 catch(Exception e) {\r
129                                         if(i == addresses.Length - 1){\r
130                                                 if(socket != null) {\r
131                                                         socket.Close();\r
132                                                         socket = null;\r
133                                                 }\r
134 \r
135                                                 /// This is the last entry, re-throw the exception\r
136                                                 throw e;\r
137                                         }\r
138                                 }\r
139                         }\r
140 \r
141                 }\r
142 #endregion\r
143                 #region Multicast methods\r
144                 public void DropMulticastGroup (IPAddress multicastAddr)\r
145                 {\r
146                         CheckDisposed ();\r
147                         if (multicastAddr == null)\r
148                                 throw new ArgumentNullException ("multicastAddr");\r
149 \r
150                         if(family == AddressFamily.InterNetwork)\r
151                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DropMembership,\r
152                                         new MulticastOption (multicastAddr));\r
153 #if NET_1_1\r
154                         else\r
155                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DropMembership,\r
156                                         new IPv6MulticastOption (multicastAddr));\r
157 #endif\r
158                 }\r
159 \r
160                 public void JoinMulticastGroup (IPAddress multicastAddr)\r
161                 {\r
162                         CheckDisposed ();\r
163 \r
164                         if(family == AddressFamily.InterNetwork)\r
165                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership,\r
166                                         new MulticastOption (multicastAddr));\r
167 #if NET_1_1\r
168                         else\r
169                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.AddMembership,\r
170                                         new IPv6MulticastOption (multicastAddr));\r
171 #endif\r
172                 }\r
173 \r
174                 public void JoinMulticastGroup (IPAddress multicastAddr, int timeToLive)\r
175                 {\r
176                         CheckDisposed ();\r
177                         JoinMulticastGroup (multicastAddr);\r
178                         if (timeToLive < 0 || timeToLive > 255)\r
179                                 throw new ArgumentOutOfRangeException ("timeToLive");\r
180 \r
181                         if(family == AddressFamily.InterNetwork)\r
182                                 socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,\r
183                                         timeToLive);\r
184 #if NET_1_1\r
185                         else\r
186                                 socket.SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive,\r
187                                         timeToLive);\r
188 #endif\r
189                 }\r
190                 #endregion\r
191 #region Data I/O\r
192                 public byte [] Receive (ref IPEndPoint remoteEP)\r
193                 {\r
194                         CheckDisposed ();\r
195 \r
196                         // Bug 45633: the spec states that we should block until a datagram arrives:\r
197                         // remove the 512 hardcoded value.\r
198 \r
199                         // Block until we get it.\r
200                         socket.Poll (-1, SelectMode.SelectRead);\r
201                         \r
202                         byte [] recBuffer;\r
203                         int available = socket.Available;\r
204 \r
205                         recBuffer = new byte [available];\r
206                         EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);\r
207                         int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);\r
208                         if (dataRead < recBuffer.Length)\r
209                                 recBuffer = CutArray (recBuffer, dataRead);\r
210 \r
211                         remoteEP = (IPEndPoint) endPoint;\r
212                         return recBuffer;\r
213                 }\r
214 \r
215                 public int Send (byte [] dgram, int bytes)\r
216                 {\r
217                         CheckDisposed ();\r
218                         if (dgram == null)\r
219                                 throw new ArgumentNullException ("dgram");\r
220 \r
221                         if (!active)\r
222                                 throw new InvalidOperationException ("Operation not allowed on " + \r
223                                                                      "non-connected sockets.");\r
224 \r
225                         return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
226                 }\r
227 \r
228                 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)\r
229                 {\r
230                         CheckDisposed ();\r
231                         if (dgram == null)\r
232                                 throw new ArgumentNullException ("dgram is null");\r
233                         \r
234                         if (active) {\r
235                                 if (endPoint != null)\r
236                                         throw new InvalidOperationException ("Cannot send packets to an " +\r
237                                                                              "arbitrary host while connected.");\r
238 \r
239                                 return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
240                         }\r
241                         \r
242                         return socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint);\r
243                 }\r
244 \r
245                 public int Send (byte [] dgram, int bytes, string hostname, int port)\r
246                 {\r
247                         return Send (dgram, bytes, \r
248                                      new IPEndPoint (Dns.Resolve (hostname).AddressList [0], port));\r
249                 }\r
250 \r
251                 private byte [] CutArray (byte [] orig, int length)\r
252                 {\r
253                         byte [] newArray = new byte [length];\r
254                         Buffer.BlockCopy (orig, 0, newArray, 0, length);\r
255 \r
256                         return newArray;\r
257                 }\r
258 #endregion\r
259 #region Properties\r
260                 protected bool Active {\r
261                         get { return active; }\r
262                         set { active = value; }\r
263                 }\r
264 \r
265                 protected Socket Client {\r
266                         get { return socket; }\r
267                         set { socket = value; }\r
268                 }\r
269 #endregion\r
270 #region Disposing\r
271                 void IDisposable.Dispose ()\r
272                 {\r
273                         Dispose (true);\r
274                         GC.SuppressFinalize (this);\r
275                 }\r
276 \r
277                 void Dispose (bool disposing)\r
278                 {\r
279                         if (disposed) \r
280                                 return;\r
281                         disposed = true;\r
282                         if (disposing) {\r
283                                 // release managed resources\r
284                         }                       \r
285                         // release unmanaged resources\r
286                         Socket s = socket;\r
287                         socket = null;\r
288                         if (s != null)\r
289                                 s.Close ();\r
290                 }\r
291                 \r
292                 ~UdpClient ()\r
293                 {\r
294                         Dispose (false);\r
295                 }\r
296                 \r
297                 private void CheckDisposed ()\r
298                 {\r
299                         if (disposed)\r
300                                 throw new ObjectDisposedException (GetType().FullName);\r
301                 }               \r
302 #endregion\r
303 #endregion\r
304         }\r
305 }\r
306 \r