726606e68b29abfe365846b6cb977f9407f5fd26
[mono.git] / mcs / class / System / System.Net / Dns.cs
1 // System.Net.Dns.cs
2 //
3 // Author: Mads Pultz (mpultz@diku.dk)
4 //
5 // (C) Mads Pultz, 2001
6
7 using System;
8 using System.Net.Sockets;
9 using System.Text;
10 using System.Collections;
11 using System.Runtime.InteropServices;
12
13 namespace System.Net {
14
15         public sealed class Dns {
16                 
17                 /// <summary>
18                 ///     This class conforms to the C structure <c>hostent</c> and is used
19                 ///     by the Dns class when doing native calls.
20                 /// </summary>
21                 [StructLayout(LayoutKind.Sequential)]
22                 private unsafe class Hostent {
23                         public string h_name;       /* official name */
24                         public byte** h_aliases;    /* alias list */
25                         public short h_addrtype;    /* address type */
26                         public short h_length;      /* address length */
27                         public byte** h_addr_list;  /* address list */
28                 }
29                 
30                 public static IAsyncResult BeginGetHostByName(string hostName,
31                                                   AsyncCallback requestCallback,
32                                                   object stateObject) {
33                         // TODO
34                         throw new NotImplementedException();
35                 }
36                 
37                 public static IAsyncResult BeginResolve(string hostName,
38                                                 AsyncCallback requestCallback,
39                                                 object stateObject) {
40                         // TODO
41                         throw new NotImplementedException();
42                 }
43                 
44                 public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) {
45                         // TODO
46                         throw new NotImplementedException();
47                 }
48                 
49                 public static IPHostEntry EndResolve(IAsyncResult asyncResult) {
50                         // TODO
51                         throw new NotImplementedException();
52                 }
53                 
54                 /// <param name=hostName>
55                 ///             IP address in network byte order (e.g. Big-Endian).
56                 ///     </param>
57                 /// <param name=length>
58                 ///             Length of IP address
59                 /// </param>
60                 /// <param name=type>
61                 ///             Type (should be 2, equals AF_INET)
62                 /// </param>
63                 [DllImport("cygwin1", EntryPoint="gethostbyaddr")]
64                 private static extern IntPtr _GetHostByAddress(byte[] hostName,
65                                                                short length,
66                                                                short type);
67                 
68                 /// <param name=address>
69                 ///             IP address in network byte order (e.g. Big-Endian).
70                 /// </param>
71                 private static IPHostEntry GetHostByAddress(long address) {
72                         short length = 4;
73                         if (address > uint.MaxValue)
74                                 length = 8;
75                         byte[] addr = new byte[length];
76                         for(int i = length - 1, j = 0; i >= 0; --i, ++j) {
77                                 byte b = (byte)(address >> i * 8);
78 //                              Console.WriteLine(b);
79                                 addr[j] = b;
80                         }
81                         IntPtr p = _GetHostByAddress(addr, length, 2);  // TODO: set type
82                         if (p == IntPtr.Zero)
83                                 throw new SocketException();  // TODO: set error code
84                         Hostent h = new Hostent();
85                         System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
86                         return ToIPHostEntry(h);
87                 }
88                 
89                 public static IPHostEntry GetHostByAddress(IPAddress address) {
90                         if (address == null)
91                                 throw new ArgumentNullException();
92                         return GetHostByAddress(IPAddress.HostToNetworkOrder(address.Address));
93                 }
94                 
95                 public static IPHostEntry GetHostByAddress(string address) {
96                         if (address == null)
97                                 throw new ArgumentNullException();
98                         return GetHostByAddress(CreateAddress(address));
99                 }
100                 
101 /*
102     [DllImport("cygwin1", EntryPoint="h_errno")]
103         private static extern int _h_errno;
104 */
105
106                 [DllImport("cygwin1", EntryPoint="gethostbyname")]
107                 private static extern IntPtr _GetHostByName(string hostName);
108                 
109                 public static IPHostEntry GetHostByName(string hostName) {
110                         if (hostName == null)
111                                 throw new ArgumentNullException();
112                         IntPtr p = _GetHostByName(hostName);
113                         //        int errNo = _h_errno;
114                         if (p == IntPtr.Zero)
115                                 throw new SocketException();  // TODO: set error code
116                         Hostent h = new Hostent();
117                         System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
118                         return ToIPHostEntry(h);
119                 }
120                 
121                 /// <summary>
122                 ///     This method returns the host name associated with the local host.
123                 /// </summary>
124                 public static string GetHostName() {
125                         IPHostEntry h = GetHostByAddress("127.0.0.1");
126                         return h.HostName;
127                 }
128                 
129                 /// <param name=address>
130                 ///     IP address in Little-Endian byte order.
131                 /// </param>
132                 /// <returns>
133                 ///     IP address in dotted notation form.
134                 /// </returns>
135                 public static string IpToString(int address) {
136                         address = IPAddress.HostToNetworkOrder(address);
137                         StringBuilder res = new StringBuilder();
138                         for(int i = 3; i > 0; --i) {
139                                 byte b = (byte)(address >> i * 8);
140                                 res.Append(b);
141                                 res.Append('.');
142                         }
143                         res.Append((byte)address);
144                         return res.ToString();
145                 }
146                 
147                 /// <summary>
148                 ///     This method resovles a DNS-style host name or IP
149                 ///     address.
150                 /// </summary>
151                 /// <param name=hostName>
152                 ///     A string containing either a DNS-style host name (e.g.
153                 ///     www.go-mono.com) or IP address (e.g. 129.250.184.233).
154                 /// </param>
155                 public static IPHostEntry Resolve(string hostName) {
156                         if (hostName == null)
157                                 throw new ArgumentNullException();
158                         try {
159                                 long addr = CreateAddress(hostName);
160                                 if (addr > uint.MaxValue)
161                                         throw new FormatException("Only IP version 4 addresses are supported");
162                                 return GetHostByAddress(addr);
163                         } catch (FormatException) {
164                           return GetHostByName(hostName);
165                         }
166                 }
167                 
168                 /// <summary>
169                 ///     Utility method. This method converts a Hostent instance to a
170                 ///     IPHostEntry instance.
171                 /// </summary>
172                 /// <param name=h>
173                 ///     Object which should be mapped to a IPHostEntry instance.
174                 /// </param>
175                 private static unsafe IPHostEntry ToIPHostEntry(Hostent h) {
176                         IPHostEntry res = new IPHostEntry();
177                         
178                         // Set host name
179                         res.HostName = h.h_name;
180                         
181                         // Set IP address list
182                         byte** p = h.h_addr_list;
183                         ArrayList tmp = new ArrayList(1);
184                         while (*p != null) {
185                                 tmp.Add(CreateIPAddress(*p, h.h_length));
186                                 ++p;
187                         }
188                         IPAddress[] addr_list = new IPAddress[tmp.Count];
189                         for(int i = 0; i < tmp.Count; ++i)
190                                 addr_list[i] = (IPAddress)tmp[i];
191                         res.AddressList = addr_list;
192                         
193                         // Set IP aliases
194                         p = h.h_aliases;
195                         tmp.Clear();
196                         while (*p != null) {
197                                 tmp.Add(new string((sbyte*)*p));
198                                 ++p;
199                         }
200                         string[] aliases = new string[tmp.Count];
201                         for(int i = 0; i < tmp.Count; ++i)
202                                 aliases[i] = (string)tmp[i];
203                         res.Aliases = aliases;
204                         
205                         return res;
206                 }
207                 
208                 /// <summary>
209                 ///     Utility method. Convert IP address in dotted notation
210                 ///     to IP address.
211                 /// </summary>
212                 private static long CreateAddress(string address) {
213                         string[] tokens = address.Split('.');
214                         if (tokens.Length % 4 != 0)
215                                 throw new FormatException("IP address has invalid length");
216                         long addr = 0;
217                         for(int i = 0, j = tokens.Length - 1; i < tokens.Length; ++i, --j) {
218                                 try {
219                                         addr = addr | (((long)byte.Parse(tokens[i])) << j * 8);
220                                 } catch (OverflowException) {
221                                         throw new FormatException("Invalid IP address format");
222                                 }
223                         }
224                         return addr;
225                 }
226         
227                 /// <summary>
228                 ///     Utility method. This method creates a IP address.
229                 /// </summary>
230                 /// <param name=addr>
231                 ///     IP address in network byte order (e.g. Big-Endian).
232                 /// </param>
233                 /// <param name=length>
234                 ///     Length of IP address (4 or 8 bytes).
235                 /// </param>
236                 private static unsafe IPAddress CreateIPAddress(byte* addr, short length) {
237                         byte* p = addr;
238                         long res = 0;
239                         for(int i = 0, j = length - 1; i < length; ++i, --j) {
240                                 res += *p << j * 8;
241                                 ++p;
242                         }
243                         if (res > uint.MaxValue)
244                                 return new IPAddress(IPAddress.NetworkToHostOrder(res));
245                         else
246                                 return new IPAddress(IPAddress.NetworkToHostOrder((int)res));
247                 }
248         }
249 }
250