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;
112 public static IAsyncResult BeginResolve(string hostName,
113 AsyncCallback requestCallback,
114 object stateObject) {
116 throw new NotImplementedException();
119 public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) {
120 return ((DnsAsyncResult)asyncResult).Worker.Result;
123 public static IPHostEntry EndResolve(IAsyncResult asyncResult) {
125 throw new NotImplementedException();
128 /// <param name=hostName>
129 /// IP address in network byte order (e.g. Big-Endian).
131 /// <param name=length>
132 /// Length of IP address.
134 /// <param name=type>
135 /// Type (should be 2, equals AF_INET).
137 [DllImport("cygwin1", EntryPoint="gethostbyaddr")]
138 private static extern IntPtr _GetHostByAddress(byte[] hostName,
142 /// <param name=address>
143 /// IP address in network byte order (e.g. Big-Endian).
145 private static IPHostEntry GetHostByAddress(long address) {
147 if (address > uint.MaxValue)
149 byte[] addr = new byte[length];
150 for(int i = length - 1, j = 0; i >= 0; --i, ++j) {
151 byte b = (byte)(address >> i * 8);
152 // Console.WriteLine(b);
155 IntPtr p = _GetHostByAddress(addr, length, 2); // TODO: set type
156 if (p == IntPtr.Zero)
157 throw new SocketException(); // TODO: set error code
158 Hostent h = new Hostent();
159 System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
160 return ToIPHostEntry(h);
163 public static IPHostEntry GetHostByAddress(IPAddress address) {
165 throw new ArgumentNullException();
166 return GetHostByAddress(IPAddress.HostToNetworkOrder(address.Address));
169 public static IPHostEntry GetHostByAddress(string address) {
171 throw new ArgumentNullException();
172 return GetHostByAddress(CreateAddress(address));
175 [DllImport("cygwin1", EntryPoint="gethostbyname")]
176 private static extern IntPtr _GetHostByName(string hostName);
178 public static IPHostEntry GetHostByName(string hostName) {
179 if (hostName == null)
180 throw new ArgumentNullException();
181 IntPtr p = _GetHostByName(hostName);
182 // int errNo = _h_errno;
183 if (p == IntPtr.Zero)
184 throw new SocketException(); // TODO: set error code
185 Hostent h = new Hostent();
186 System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
187 return ToIPHostEntry(h);
191 /// This method returns the host name associated with the local host.
193 public static string GetHostName() {
194 IPHostEntry h = GetHostByAddress("127.0.0.1");
198 /// <param name=address>
199 /// IP address in Little-Endian byte order.
202 /// IP address in dotted notation form.
204 public static string IpToString(int address) {
205 address = IPAddress.HostToNetworkOrder(address);
206 StringBuilder res = new StringBuilder();
207 for(int i = 3; i > 0; --i) {
208 byte b = (byte)(address >> i * 8);
212 res.Append((byte)address);
213 return res.ToString();
217 /// This method resovles a DNS-style host name or IP
220 /// <param name=hostName>
221 /// A string containing either a DNS-style host name (e.g.
222 /// www.go-mono.com) or IP address (e.g. 129.250.184.233).
224 public static IPHostEntry Resolve(string hostName) {
225 if (hostName == null)
226 throw new ArgumentNullException();
228 long addr = CreateAddress(hostName);
229 if (addr > uint.MaxValue)
230 throw new FormatException("Only IP version 4 addresses are supported");
231 return GetHostByAddress(addr);
232 } catch (FormatException) {
233 return GetHostByName(hostName);
238 /// Utility method. This method converts a Hostent instance to a
239 /// IPHostEntry instance.
242 /// Object which should be mapped to a IPHostEntry instance.
244 private static unsafe IPHostEntry ToIPHostEntry(Hostent h) {
245 IPHostEntry res = new IPHostEntry();
248 res.HostName = h.h_name;
250 // Set IP address list
251 byte** p = h.h_addr_list;
252 ArrayList tmp = new ArrayList(1);
254 tmp.Add(CreateIPAddress(*p, h.h_length));
257 IPAddress[] addr_list = new IPAddress[tmp.Count];
258 for(int i = 0; i < tmp.Count; ++i)
259 addr_list[i] = (IPAddress)tmp[i];
260 res.AddressList = addr_list;
266 tmp.Add(new string((sbyte*)*p));
269 string[] aliases = new string[tmp.Count];
270 for(int i = 0; i < tmp.Count; ++i)
271 aliases[i] = (string)tmp[i];
272 res.Aliases = aliases;
278 /// Utility method. Convert IP address in dotted notation
281 private static long CreateAddress(string address) {
282 string[] tokens = address.Split('.');
283 if (tokens.Length % 4 != 0)
284 throw new FormatException("IP address has invalid length");
286 for(int i = 0, j = tokens.Length - 1; i < tokens.Length; ++i, --j) {
288 addr = addr | (((long)byte.Parse(tokens[i])) << j * 8);
289 } catch (OverflowException) {
290 throw new FormatException("Invalid IP address format");
297 /// Utility method. This method creates a IP address.
299 /// <param name=addr>
300 /// IP address in network byte order (e.g. Big-Endian).
302 /// <param name=length>
303 /// Length of IP address (4 or 8 bytes).
305 private static unsafe IPAddress CreateIPAddress(byte* addr, short length) {
308 for(int i = 0, j = length - 1; i < length; ++i, --j) {
312 if (res > uint.MaxValue)
313 return new IPAddress(IPAddress.NetworkToHostOrder(res));
315 return new IPAddress(IPAddress.NetworkToHostOrder((int)res));