Unbreak the build
[mono.git] / mcs / class / System / System.Net / Dns.cs
1 // System.Net.Dns.cs
2 //
3 // Authors:
4 //      Mads Pultz (mpultz@diku.dk)
5 //      Lawrence Pit (loz@cable.a2000.nl)
6
7 // Author: Mads Pultz (mpultz@diku.dk)
8 //         Lawrence Pit (loz@cable.a2000.nl)
9 //         Marek Safar (marek.safar@gmail.com)
10 //         Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
11 //
12 // (C) Mads Pultz, 2001
13 // Copyright (c) 2011 Novell, Inc.
14 // Copyright (c) 2011 Xamarin, Inc.
15
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Net.Sockets;
39 using System.Text;
40 using System.Collections;
41 using System.Threading;
42 using System.Runtime.CompilerServices;
43 using System.Runtime.Remoting.Messaging;
44 #if NET_4_5
45 using System.Threading.Tasks;
46 #endif
47
48 using Mono.Dns;
49
50 namespace System.Net {
51         public static class Dns {
52                 static bool use_mono_dns;
53                 static SimpleResolver resolver;
54
55                 static Dns ()
56                 {
57                         System.Net.Sockets.Socket.CheckProtocolSupport();
58                         if (Environment.GetEnvironmentVariable ("MONO_DNS") != null) {
59                                 resolver = new SimpleResolver ();
60                                 use_mono_dns = true;
61                         }
62                 }
63
64                 internal static bool UseMonoDns {
65                         get { return use_mono_dns; }
66                 }
67
68 #if !MOONLIGHT // global remove of async methods
69
70                 private delegate IPHostEntry GetHostByNameCallback (string hostName);
71                 private delegate IPHostEntry ResolveCallback (string hostName);
72                 private delegate IPHostEntry GetHostEntryNameCallback (string hostName);
73                 private delegate IPHostEntry GetHostEntryIPCallback (IPAddress hostAddress);
74                 private delegate IPAddress [] GetHostAddressesCallback (string hostName);
75
76                 static void OnCompleted (object sender, SimpleResolverEventArgs e)
77                 {
78                         DnsAsyncResult ares = (DnsAsyncResult) e.UserToken;
79                         IPHostEntry entry = e.HostEntry;
80                         if (entry == null || e.ResolverError != 0) {
81                                 ares.SetCompleted (false, new Exception ("Error: " + e.ResolverError));
82                                 return;
83                         }
84                         ares.SetCompleted (false, entry);
85                 }
86
87                 static IAsyncResult BeginAsyncCallAddresses (string host, AsyncCallback callback, object state)
88                 {
89                         SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
90                         e.Completed += OnCompleted;
91                         e.HostName = host;
92                         DnsAsyncResult ares = new DnsAsyncResult (callback, state);
93                         e.UserToken = ares;
94                         if (resolver.GetHostAddressesAsync (e) == false)
95                                 ares.SetCompleted (true, e.HostEntry); // Completed synchronously
96                         return ares;
97                 }
98
99                 static IAsyncResult BeginAsyncCall (string host, AsyncCallback callback, object state)
100                 {
101                         SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
102                         e.Completed += OnCompleted;
103                         e.HostName = host;
104                         DnsAsyncResult ares = new DnsAsyncResult (callback, state);
105                         e.UserToken = ares;
106                         if (resolver.GetHostEntryAsync (e) == false)
107                                 ares.SetCompleted (true, e.HostEntry); // Completed synchronously
108                         return ares;
109                 }
110
111                 static IPHostEntry EndAsyncCall (DnsAsyncResult ares)
112                 {
113                         if (ares == null)
114                                 throw new ArgumentException ("Invalid asyncResult");
115                         if (!ares.IsCompleted)
116                                 ares.AsyncWaitHandle.WaitOne ();
117                         if (ares.Exception != null)
118                                 throw ares.Exception;
119                         IPHostEntry entry = ares.HostEntry;
120                         if (entry == null || entry.AddressList == null || entry.AddressList.Length == 0)
121                                 throw new SocketException(11001);
122                         return entry;
123                 }
124
125                 [Obsolete ("Use BeginGetHostEntry instead")]
126                 public static IAsyncResult BeginGetHostByName (string hostName, AsyncCallback requestCallback, object stateObject)
127                 {
128                         if (hostName == null)
129                                 throw new ArgumentNullException ("hostName");
130
131                         if (use_mono_dns)
132                                 return BeginAsyncCall (hostName, requestCallback, stateObject);
133
134                         GetHostByNameCallback c = new GetHostByNameCallback (GetHostByName);
135                         return c.BeginInvoke (hostName, requestCallback, stateObject);
136                 }
137
138                 [Obsolete ("Use BeginGetHostEntry instead")]
139                 public static IAsyncResult BeginResolve (string hostName, AsyncCallback requestCallback, object stateObject)
140                 {
141                         if (hostName == null)
142                                 throw new ArgumentNullException ("hostName");
143
144                         if (use_mono_dns)
145                                 return BeginAsyncCall (hostName, requestCallback, stateObject);
146
147                         ResolveCallback c = new ResolveCallback (Resolve);
148                         return c.BeginInvoke (hostName, requestCallback, stateObject);
149                 }
150
151                 public static IAsyncResult BeginGetHostAddresses (string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
152                 {
153                         if (hostNameOrAddress == null)
154                                 throw new ArgumentNullException ("hostName");
155                         if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
156                                 throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
157                                         "and ::0 (IPv6) are unspecified addresses. You " +
158                                         "cannot use them as target address.",
159                                         "hostNameOrAddress");
160
161                         if (use_mono_dns)
162                                 return BeginAsyncCallAddresses (hostNameOrAddress, requestCallback, stateObject);
163
164                         GetHostAddressesCallback c = new GetHostAddressesCallback (GetHostAddresses);
165                         return c.BeginInvoke (hostNameOrAddress, requestCallback, stateObject);
166                 }
167
168                 public static IAsyncResult BeginGetHostEntry (string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
169                 {
170                         if (hostNameOrAddress == null)
171                                 throw new ArgumentNullException ("hostName");
172                         if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
173                                 throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
174                                         "and ::0 (IPv6) are unspecified addresses. You " +
175                                         "cannot use them as target address.",
176                                         "hostNameOrAddress");
177
178                         if (use_mono_dns)
179                                 return BeginAsyncCall (hostNameOrAddress, requestCallback, stateObject);
180
181                         GetHostEntryNameCallback c = new GetHostEntryNameCallback (GetHostEntry);
182                         return c.BeginInvoke (hostNameOrAddress, requestCallback, stateObject);
183                 }
184
185                 public static IAsyncResult BeginGetHostEntry (IPAddress address, AsyncCallback requestCallback, object stateObject)
186                 {
187                         if (address == null)
188                                 throw new ArgumentNullException ("address");
189
190                         if (use_mono_dns)
191                                 return BeginAsyncCall (address.ToString (), requestCallback, stateObject);
192
193                         GetHostEntryIPCallback c = new GetHostEntryIPCallback (GetHostEntry);
194                         return c.BeginInvoke (address, requestCallback, stateObject);
195                 }
196
197                 [Obsolete ("Use EndGetHostEntry instead")]
198                 public static IPHostEntry EndGetHostByName (IAsyncResult asyncResult) 
199                 {
200                         if (asyncResult == null)
201                                 throw new ArgumentNullException ("asyncResult");
202
203                         if (use_mono_dns)
204                                 return EndAsyncCall (asyncResult as DnsAsyncResult);
205
206                         AsyncResult async = (AsyncResult) asyncResult;
207                         GetHostByNameCallback cb = (GetHostByNameCallback) async.AsyncDelegate;
208                         return cb.EndInvoke(asyncResult);
209                 }
210
211                 [Obsolete ("Use EndGetHostEntry instead")]
212                 public static IPHostEntry EndResolve (IAsyncResult asyncResult) 
213                 {
214                         if (asyncResult == null)
215                                 throw new ArgumentNullException ("asyncResult");
216
217                         if (use_mono_dns)
218                                 return EndAsyncCall (asyncResult as DnsAsyncResult);
219
220                         AsyncResult async = (AsyncResult) asyncResult;
221                         ResolveCallback cb = (ResolveCallback) async.AsyncDelegate;
222                         return cb.EndInvoke(asyncResult);
223                 }
224
225                 public static IPAddress [] EndGetHostAddresses (IAsyncResult asyncResult) 
226                 {
227                         if (asyncResult == null)
228                                 throw new ArgumentNullException ("asyncResult");
229
230                         if (use_mono_dns) {
231                                 IPHostEntry entry = EndAsyncCall (asyncResult as DnsAsyncResult);
232                                 if (entry == null)
233                                         return null;
234                                 return entry.AddressList;
235                         }
236
237                         AsyncResult async = (AsyncResult) asyncResult;
238                         GetHostAddressesCallback cb = (GetHostAddressesCallback) async.AsyncDelegate;
239                         return cb.EndInvoke(asyncResult);
240                 }
241
242                 public static IPHostEntry EndGetHostEntry (IAsyncResult asyncResult) 
243                 {
244                         if (asyncResult == null)
245                                 throw new ArgumentNullException ("asyncResult");
246
247                         if (use_mono_dns)
248                                 return EndAsyncCall (asyncResult as DnsAsyncResult);
249
250                         AsyncResult async = (AsyncResult) asyncResult;
251                         if (async.AsyncDelegate is GetHostEntryIPCallback)
252                                 return ((GetHostEntryIPCallback) async.AsyncDelegate).EndInvoke (asyncResult);
253                         GetHostEntryNameCallback cb = (GetHostEntryNameCallback) async.AsyncDelegate;
254                         return cb.EndInvoke(asyncResult);
255                 }
256                 
257 #endif // !MOONLIGHT: global remove of async methods
258
259 #if !TARGET_JVM
260                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
261                 private extern static bool GetHostByName_internal(string host, out string h_name, out string[] h_aliases, out string[] h_addr_list);
262
263                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
264                 private extern static bool GetHostByAddr_internal(string addr, out string h_name, out string[] h_aliases, out string[] h_addr_list);
265
266                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
267                 private extern static bool GetHostName_internal(out string h_name);
268 #endif  
269
270                 private static IPHostEntry hostent_to_IPHostEntry(string h_name, string[] h_aliases, string[] h_addrlist) 
271                 {
272                         IPHostEntry he = new IPHostEntry();
273                         ArrayList addrlist = new ArrayList();
274
275                         he.HostName = h_name;
276                         he.Aliases = h_aliases;
277                         for(int i=0; i<h_addrlist.Length; i++) {
278                                 try {
279                                         IPAddress newAddress = IPAddress.Parse(h_addrlist[i]);
280
281                                         if( (Socket.SupportsIPv6 && newAddress.AddressFamily == AddressFamily.InterNetworkV6) ||
282                                             (Socket.SupportsIPv4 && newAddress.AddressFamily == AddressFamily.InterNetwork) )
283                                                 addrlist.Add(newAddress);
284                                 } catch (ArgumentNullException) {
285                                         /* Ignore this, as the
286                                          * internal call might have
287                                          * left some blank entries at
288                                          * the end of the array
289                                          */
290                                 }
291                         }
292
293                         if(addrlist.Count == 0)
294                                 throw new SocketException(11001);
295
296                         he.AddressList = addrlist.ToArray(typeof(IPAddress)) as IPAddress[];
297                         return he;
298                 }
299
300                 [Obsolete ("Use GetHostEntry instead")]
301                 public static IPHostEntry GetHostByAddress(IPAddress address)
302                 {
303                         if (address == null)
304                                 throw new ArgumentNullException ("address");
305
306                         return GetHostByAddressFromString (address.ToString (), false);
307                 }
308
309                 [Obsolete ("Use GetHostEntry instead")]
310                 public static IPHostEntry GetHostByAddress(string address)
311                 {
312                         if (address == null)
313                                 throw new ArgumentNullException ("address");
314
315                         return GetHostByAddressFromString (address, true);
316                 }
317
318                 static IPHostEntry GetHostByAddressFromString (string address, bool parse)
319                 {
320                         // Undocumented MS behavior: when called with IF_ANY,
321                         // this should return the local host
322                         if (address.Equals ("0.0.0.0")) {
323                                 address = "127.0.0.1";
324                                 parse = false;
325                         }
326
327                         // Must check the IP format, might send an exception if invalid string.
328                         if (parse)
329                                 IPAddress.Parse (address);
330
331                         string h_name;
332                         string[] h_aliases, h_addrlist;
333 #if TARGET_JVM
334                         h_name = null;
335                         h_aliases = null;
336                         h_addrlist = null;
337                         try {
338                                 java.net.InetAddress[] iaArr = 
339                                         java.net.InetAddress.getAllByName(address);
340                                 if (iaArr != null && iaArr.Length > 0)
341                                     h_name = iaArr[0].getHostName();
342                                 if (iaArr != null && iaArr.Length > 0)
343                                 {
344                                     h_addrlist = new String[iaArr.Length];
345                                     for (int i = 0; i < h_addrlist.Length; i++)
346                                         h_addrlist[i] = iaArr[i].getHostAddress();
347                                 }
348                         } catch (java.net.UnknownHostException jUHE) {
349                                 throw new SocketException((int)SocketError.HostNotFound, jUHE.Message);
350                         }
351 #else
352                         bool ret = GetHostByAddr_internal(address, out h_name, out h_aliases, out h_addrlist);
353                         if (!ret)
354                                 throw new SocketException(11001);
355 #endif
356                         return (hostent_to_IPHostEntry (h_name, h_aliases, h_addrlist));
357                         
358                 }
359
360                 public static IPHostEntry GetHostEntry (string hostNameOrAddress)
361                 {
362                         if (hostNameOrAddress == null)
363                                 throw new ArgumentNullException ("hostNameOrAddress");
364                         if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
365                                 throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
366                                         "and ::0 (IPv6) are unspecified addresses. You " +
367                                         "cannot use them as target address.",
368                                         "hostNameOrAddress");
369
370                         IPAddress addr;
371                         if (hostNameOrAddress.Length > 0 && IPAddress.TryParse (hostNameOrAddress, out addr))
372                                 return GetHostEntry (addr);
373
374                         return GetHostByName (hostNameOrAddress);
375                 }
376
377                 public static IPHostEntry GetHostEntry (IPAddress address)
378                 {
379                         if (address == null)
380                                 throw new ArgumentNullException ("address");
381
382                         return GetHostByAddressFromString (address.ToString (), false);
383                 }
384
385                 public static IPAddress [] GetHostAddresses (string hostNameOrAddress)
386                 {
387                         if (hostNameOrAddress == null)
388                                 throw new ArgumentNullException ("hostNameOrAddress");
389
390                         if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
391                                 throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
392                                         "and ::0 (IPv6) are unspecified addresses. You " +
393                                         "cannot use them as target address.",
394                                         "hostNameOrAddress");
395
396                         IPAddress addr;
397                         if (hostNameOrAddress.Length > 0 && IPAddress.TryParse (hostNameOrAddress, out addr))
398                                 return new IPAddress[1] { addr };
399
400                         return GetHostEntry (hostNameOrAddress).AddressList;
401                 }
402
403                 [Obsolete ("Use GetHostEntry instead")]
404                 public static IPHostEntry GetHostByName (string hostName)
405                 {
406                         if (hostName == null)
407                                 throw new ArgumentNullException ("hostName");
408 #if TARGET_JVM
409                         if (hostName.Length == 0)
410                                 hostName = "localhost";
411                         try {
412                                 java.net.InetAddress[] iaArr = java.net.InetAddress.getAllByName(hostName);
413                                 IPHostEntry host = new IPHostEntry();
414                                 if (iaArr != null && iaArr.Length > 0)
415                                 {
416                                         host.HostName = iaArr[0].getHostName();
417                                         IPAddress[] ipArr = new IPAddress[iaArr.Length];
418                                         for (int i = 0; i < iaArr.Length; i++)
419                                                 ipArr[i] = IPAddress.Parse(iaArr[i].getHostAddress());
420
421                                         host.AddressList = ipArr;
422                                 }
423                                 return host;
424                         } catch (java.net.UnknownHostException jUHE) {
425                                 throw new SocketException((int)SocketError.HostNotFound, jUHE.Message);
426                         }
427 #else
428                         string h_name;
429                         string[] h_aliases, h_addrlist;
430
431                         bool ret = GetHostByName_internal(hostName, out h_name, out h_aliases, out h_addrlist);
432                         if (ret == false)
433                                 throw new SocketException(11001);
434
435                         return(hostent_to_IPHostEntry(h_name, h_aliases, h_addrlist));
436 #endif
437                 }
438
439                 public static string GetHostName ()
440                 {
441 #if TARGET_JVM
442                         return java.net.InetAddress.getLocalHost ().getHostName ();
443 #else
444                         string hostName;
445
446                         bool ret = GetHostName_internal(out hostName);
447
448                         if (ret == false)
449                                 throw new SocketException(11001);
450
451                         return hostName;
452 #endif
453                 }
454
455                 [Obsolete ("Use GetHostEntry instead")]
456                 public static IPHostEntry Resolve(string hostName) 
457                 {
458                         if (hostName == null)
459                                 throw new ArgumentNullException ("hostName");
460
461                         IPHostEntry ret = null;
462
463                         try {
464                                 ret =  GetHostByAddress(hostName);
465                         }
466                         catch{}
467
468                         if(ret == null)
469                                 ret =  GetHostByName(hostName);
470
471                         return ret;
472                 }
473
474 #if NET_4_5
475                 public static Task<IPAddress[]> GetHostAddressesAsync (string hostNameOrAddress)
476                 {
477                         return Task<IPAddress[]>.Factory.FromAsync (BeginGetHostAddresses, EndGetHostAddresses, hostNameOrAddress, null);
478                 }
479
480                 public static Task<IPHostEntry> GetHostEntryAsync (IPAddress address)
481                 {
482                         return Task<IPHostEntry>.Factory.FromAsync (BeginGetHostEntry, EndGetHostEntry, address, null);
483                 }
484
485                 public static Task<IPHostEntry> GetHostEntryAsync (string hostNameOrAddress)
486                 {
487                         return Task<IPHostEntry>.Factory.FromAsync (BeginGetHostEntry, EndGetHostEntry, hostNameOrAddress, null);
488                 }
489 #endif
490         }
491 }
492