2003-07-14 Jerome Laban <jlaban@wanadoo.fr>
[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                         // Length of the array for receiving data??\r
196                         byte [] recBuffer;\r
197                         int available = socket.Available;\r
198                         if (available < 512)\r
199                                 available = 512;\r
200 \r
201                         recBuffer = new byte [available];\r
202                         EndPoint endPoint = new IPEndPoint (IPAddress.Any, 0);\r
203                         int dataRead = socket.ReceiveFrom (recBuffer, ref endPoint);\r
204                         if (dataRead < recBuffer.Length)\r
205                                 recBuffer = CutArray (recBuffer, dataRead);\r
206 \r
207                         remoteEP = (IPEndPoint) endPoint;\r
208                         return recBuffer;\r
209                 }\r
210 \r
211                 public int Send (byte [] dgram, int bytes)\r
212                 {\r
213                         CheckDisposed ();\r
214                         if (dgram == null)\r
215                                 throw new ArgumentNullException ("dgram");\r
216 \r
217                         if (!active)\r
218                                 throw new InvalidOperationException ("Operation not allowed on " + \r
219                                                                      "non-connected sockets.");\r
220 \r
221                         return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
222                 }\r
223 \r
224                 public int Send (byte [] dgram, int bytes, IPEndPoint endPoint)\r
225                 {\r
226                         CheckDisposed ();\r
227                         if (dgram == null)\r
228                                 throw new ArgumentNullException ("dgram is null");\r
229                         \r
230                         if (active) {\r
231                                 if (endPoint != null)\r
232                                         throw new InvalidOperationException ("Cannot send packets to an " +\r
233                                                                              "arbitrary host while connected.");\r
234 \r
235                                 return socket.Send (dgram, 0, bytes, SocketFlags.None);\r
236                         }\r
237                         \r
238                         return socket.SendTo (dgram, 0, bytes, SocketFlags.None, endPoint);\r
239                 }\r
240 \r
241                 public int Send (byte [] dgram, int bytes, string hostname, int port)\r
242                 {\r
243                         return Send (dgram, bytes, \r
244                                      new IPEndPoint (Dns.Resolve (hostname).AddressList [0], port));\r
245                 }\r
246 \r
247                 private byte [] CutArray (byte [] orig, int length)\r
248                 {\r
249                         byte [] newArray = new byte [length];\r
250                         Buffer.BlockCopy (orig, 0, newArray, 0, length);\r
251 \r
252                         return newArray;\r
253                 }\r
254 #endregion\r
255 #region Properties\r
256                 protected bool Active {\r
257                         get { return active; }\r
258                         set { active = value; }\r
259                 }\r
260 \r
261                 protected Socket Client {\r
262                         get { return socket; }\r
263                         set { socket = value; }\r
264                 }\r
265 #endregion\r
266 #region Disposing\r
267                 void IDisposable.Dispose ()\r
268                 {\r
269                         Dispose (true);\r
270                         GC.SuppressFinalize (this);\r
271                 }\r
272 \r
273                 void Dispose (bool disposing)\r
274                 {\r
275                         if (disposed) \r
276                                 return;\r
277                         disposed = true;\r
278                         if (disposing) {\r
279                                 // release managed resources\r
280                         }                       \r
281                         // release unmanaged resources\r
282                         Socket s = socket;\r
283                         socket = null;\r
284                         if (s != null)\r
285                                 s.Close ();\r
286                 }\r
287                 \r
288                 ~UdpClient ()\r
289                 {\r
290                         Dispose (false);\r
291                 }\r
292                 \r
293                 private void CheckDisposed ()\r
294                 {\r
295                         if (disposed)\r
296                                 throw new ObjectDisposedException (GetType().FullName);\r
297                 }               \r
298 #endregion\r
299 #endregion\r
300         }\r
301 }\r
302 \r