3 // Author: Mads Pultz (mpultz@diku.dk)
5 // (C) Mads Pultz, 2001
8 using System.Net.Sockets;
10 using System.Collections;
11 using System.Threading;
12 using System.Runtime.InteropServices;
13 using System.Runtime.Remoting.Messaging;
15 namespace System.Net {
17 public sealed class Dns {
22 private sealed class DnsAsyncResult: IAsyncResult {
24 private WaitHandle waitHandle;
25 private bool completedSync, completed;
26 private Worker worker;
28 public DnsAsyncResult(object state) {
30 waitHandle = new ManualResetEvent(false);
31 completedSync = completed = false;
33 public object AsyncState {
36 public WaitHandle AsyncWaitHandle {
37 set { waitHandle = value; }
38 get { return waitHandle; }
40 public bool CompletedSynchronously {
41 get { return completedSync; }
43 public bool IsCompleted {
44 set { completed = value; }
45 get { return completed; }
47 public Worker Worker {
48 set { worker = value; }
49 get { return worker; }
54 /// Helper class for asynchronous calls to DNS server
56 private sealed class Worker {
57 private AsyncCallback reqCallback;
58 private DnsAsyncResult reqRes;
60 private IPHostEntry result;
62 public Worker(string req, AsyncCallback reqCallback, DnsAsyncResult reqRes) {
64 this.reqCallback = reqCallback;
69 ((ManualResetEvent)reqRes.AsyncWaitHandle).Set();
70 reqRes.IsCompleted = true;
72 public void GetHostByName() {
74 result = Dns.GetHostByName(req);
78 public void Resolve() {
80 result = Dns.Resolve(req);
84 public IPHostEntry Result {
85 get { return result; }
90 /// This class conforms to the C structure <c>hostent</c> and is used
91 /// by the Dns class when doing native calls.
93 [StructLayout(LayoutKind.Sequential)]
94 private unsafe class Hostent {
95 public string h_name; /* official name */
96 public byte** h_aliases; /* alias list */
97 public short h_addrtype; /* address type */
98 public short h_length; /* address length */
99 public byte** h_addr_list; /* address list */
102 public static IAsyncResult BeginGetHostByName(string hostName,
103 AsyncCallback requestCallback,
104 object stateObject) {
105 DnsAsyncResult requestResult = new DnsAsyncResult(stateObject);
106 Worker worker = new Worker(hostName, requestCallback, requestResult);
107 Thread child = new Thread(new ThreadStart(worker.GetHostByName));
109 return requestResult;
113 public static IAsyncResult BeginResolve(string hostName,
114 AsyncCallback requestCallback,
115 object stateObject) {
117 throw new NotImplementedException();
120 public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) {
121 return ((DnsAsyncResult)asyncResult).Worker.Result;
125 public static IPHostEntry EndResolve(IAsyncResult asyncResult) {
127 throw new NotImplementedException();
130 /// <param name=hostName>
131 /// IP address in network byte order (e.g. Big-Endian).
133 /// <param name=length>
134 /// Length of IP address.
136 /// <param name=type>
137 /// Type (should be 2, equals AF_INET).
139 [DllImport("cygwin1", EntryPoint="gethostbyaddr")]
140 private static extern IntPtr _GetHostByAddress(byte[] hostName,
144 /// <param name=address>
145 /// IP address in network byte order (e.g. Big-Endian).
148 private static IPHostEntry GetHostByAddress(long address) {
150 if (address > uint.MaxValue)
152 byte[] addr = new byte[length];
153 for(int i = length - 1, j = 0; i >= 0; --i, ++j) {
154 byte b = (byte)(address >> i * 8);
155 // Console.WriteLine(b);
158 IntPtr p = _GetHostByAddress(addr, length, 2); // TODO: set type
159 if (p == IntPtr.Zero)
160 throw new SocketException(); // TODO: set error code
161 Hostent h = new Hostent();
162 System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
163 return ToIPHostEntry(h);
166 public static IPHostEntry GetHostByAddress(IPAddress address) {
168 throw new ArgumentNullException();
169 return GetHostByAddress(IPAddress.HostToNetworkOrder(address.Address));
172 public static IPHostEntry GetHostByAddress(string address) {
174 throw new ArgumentNullException();
175 return GetHostByAddress(CreateAddress(address));
178 [DllImport("cygwin1", EntryPoint="gethostbyname")]
179 private static extern IntPtr _GetHostByName(string hostName);
182 public static IPHostEntry GetHostByName(string hostName) {
183 if (hostName == null)
184 throw new ArgumentNullException();
185 IntPtr p = _GetHostByName(hostName);
186 // int errNo = _h_errno;
187 if (p == IntPtr.Zero)
188 throw new SocketException(); // TODO: set error code
189 Hostent h = new Hostent();
190 System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
191 return ToIPHostEntry(h);
195 /// This method returns the host name associated with the local host.
197 public static string GetHostName() {
198 IPHostEntry h = GetHostByAddress("127.0.0.1");
202 /// <param name=address>
203 /// IP address in Little-Endian byte order.
206 /// IP address in dotted notation form.
208 public static string IpToString(int address) {
209 address = IPAddress.HostToNetworkOrder(address);
210 StringBuilder res = new StringBuilder();
211 for(int i = 3; i > 0; --i) {
212 byte b = (byte)(address >> i * 8);
216 res.Append((byte)address);
217 return res.ToString();
221 /// This method resovles a DNS-style host name or IP
224 /// <param name=hostName>
225 /// A string containing either a DNS-style host name (e.g.
226 /// www.go-mono.com) or IP address (e.g. 129.250.184.233).
228 public static IPHostEntry Resolve(string hostName) {
229 if (hostName == null)
230 throw new ArgumentNullException();
232 long addr = CreateAddress(hostName);
233 if (addr > uint.MaxValue)
234 throw new FormatException("Only IP version 4 addresses are supported");
235 return GetHostByAddress(addr);
236 } catch (FormatException) {
237 return GetHostByName(hostName);
242 /// Utility method. This method converts a Hostent instance to a
243 /// IPHostEntry instance.
246 /// Object which should be mapped to a IPHostEntry instance.
248 private static unsafe IPHostEntry ToIPHostEntry(Hostent h) {
249 IPHostEntry res = new IPHostEntry();
252 res.HostName = h.h_name;
254 // Set IP address list
255 byte** p = h.h_addr_list;
256 ArrayList tmp = new ArrayList(1);
258 tmp.Add(CreateIPAddress(*p, h.h_length));
261 IPAddress[] addr_list = new IPAddress[tmp.Count];
262 for(int i = 0; i < tmp.Count; ++i)
263 addr_list[i] = (IPAddress)tmp[i];
264 res.AddressList = addr_list;
270 tmp.Add(new string((sbyte*)*p));
273 string[] aliases = new string[tmp.Count];
274 for(int i = 0; i < tmp.Count; ++i)
275 aliases[i] = (string)tmp[i];
276 res.Aliases = aliases;
282 /// Utility method. Convert IP address in dotted notation
285 private static long CreateAddress(string address) {
286 string[] tokens = address.Split('.');
287 if (tokens.Length % 4 != 0)
288 throw new FormatException("IP address has invalid length");
290 for(int i = 0, j = tokens.Length - 1; i < tokens.Length; ++i, --j) {
292 addr = addr | (((long)byte.Parse(tokens[i])) << j * 8);
293 } catch (OverflowException) {
294 throw new FormatException("Invalid IP address format");
301 /// Utility method. This method creates a IP address.
303 /// <param name=addr>
304 /// IP address in network byte order (e.g. Big-Endian).
306 /// <param name=length>
307 /// Length of IP address (4 or 8 bytes).
309 private static unsafe IPAddress CreateIPAddress(byte* addr, short length) {
312 for(int i = 0, j = length - 1; i < length; ++i, --j) {
316 if (res > uint.MaxValue)
317 return new IPAddress(IPAddress.NetworkToHostOrder(res));
319 return new IPAddress(IPAddress.NetworkToHostOrder((int)res));