Dns.cs 8.6 KB

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