| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- // System.Net.Dns.cs
- //
- // Author: Mads Pultz ([email protected])
- //
- // (C) Mads Pultz, 2001
- using System;
- using System.Net.Sockets;
- using System.Text;
- using System.Collections;
- using System.Threading;
- using System.Runtime.InteropServices;
- using System.Runtime.Remoting.Messaging;
- namespace System.Net {
- public sealed class Dns {
-
- /// <summary>
- /// Helper class
- /// </summary>
- private sealed class DnsAsyncResult: IAsyncResult {
- private object state;
- private WaitHandle waitHandle;
- private bool completedSync, completed;
- private Worker worker;
-
- public DnsAsyncResult(object state) {
- this.state = state;
- waitHandle = new ManualResetEvent(false);
- completedSync = completed = false;
- }
- public object AsyncState {
- get { return state; }
- }
- public WaitHandle AsyncWaitHandle {
- set { waitHandle = value; }
- get { return waitHandle; }
- }
- public bool CompletedSynchronously {
- get { return completedSync; }
- }
- public bool IsCompleted {
- set { completed = value; }
- get { return completed; }
- }
- public Worker Worker {
- set { worker = value; }
- get { return worker; }
- }
- }
- /// <summary>
- /// Helper class for asynchronous calls to DNS server
- /// </summary>
- private sealed class Worker {
- private AsyncCallback reqCallback;
- private DnsAsyncResult reqRes;
- private string req;
- private IPHostEntry result;
-
- public Worker(string req, AsyncCallback reqCallback, DnsAsyncResult reqRes) {
- this.req = req;
- this.reqCallback = reqCallback;
- this.reqRes = reqRes;
- }
- private void End() {
- reqCallback(reqRes);
- ((ManualResetEvent)reqRes.AsyncWaitHandle).Set();
- reqRes.IsCompleted = true;
- }
- public void GetHostByName() {
- lock(reqRes) {
- result = Dns.GetHostByName(req);
- End();
- }
- }
- public void Resolve() {
- lock(reqRes) {
- result = Dns.Resolve(req);
- End();
- }
- }
- public IPHostEntry Result {
- get { return result; }
- }
- }
-
- /// <summary>
- /// This class conforms to the C structure <c>hostent</c> and is used
- /// by the Dns class when doing native calls.
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- private unsafe class Hostent {
- public string h_name; /* official name */
- public byte** h_aliases; /* alias list */
- public short h_addrtype; /* address type */
- public short h_length; /* address length */
- public byte** h_addr_list; /* address list */
- }
-
- public static IAsyncResult BeginGetHostByName(string hostName,
- AsyncCallback requestCallback,
- object stateObject) {
- DnsAsyncResult requestResult = new DnsAsyncResult(stateObject);
- Worker worker = new Worker(hostName, requestCallback, requestResult);
- Thread child = new Thread(new ThreadStart(worker.GetHostByName));
- child.Start();
- return requestResult;
- }
- [MonoTODO]
- public static IAsyncResult BeginResolve(string hostName,
- AsyncCallback requestCallback,
- object stateObject) {
- // TODO
- throw new NotImplementedException();
- }
-
- public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) {
- return ((DnsAsyncResult)asyncResult).Worker.Result;
- }
- [MonoTODO]
- public static IPHostEntry EndResolve(IAsyncResult asyncResult) {
- // TODO
- throw new NotImplementedException();
- }
-
- /// <param name=hostName>
- /// IP address in network byte order (e.g. Big-Endian).
- /// </param>
- /// <param name=length>
- /// Length of IP address.
- /// </param>
- /// <param name=type>
- /// Type (should be 2, equals AF_INET).
- /// </param>
- [DllImport("cygwin1", EntryPoint="gethostbyaddr")]
- private static extern IntPtr _GetHostByAddress(byte[] hostName,
- short length,
- short type);
-
- /// <param name=address>
- /// IP address in network byte order (e.g. Big-Endian).
- /// </param>
- [MonoTODO]
- private static IPHostEntry GetHostByAddress(long address) {
- short length = 4;
- if (address > uint.MaxValue)
- length = 8;
- byte[] addr = new byte[length];
- for(int i = length - 1, j = 0; i >= 0; --i, ++j) {
- byte b = (byte)(address >> i * 8);
- // Console.WriteLine(b);
- addr[j] = b;
- }
- IntPtr p = _GetHostByAddress(addr, length, 2); // TODO: set type
- if (p == IntPtr.Zero)
- throw new SocketException(); // TODO: set error code
- Hostent h = new Hostent();
- System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
- return ToIPHostEntry(h);
- }
-
- public static IPHostEntry GetHostByAddress(IPAddress address) {
- if (address == null)
- throw new ArgumentNullException();
- return GetHostByAddress (IPAddress.HostToNetworkOrder (address.Address));
- }
-
- public static IPHostEntry GetHostByAddress(string address) {
- if (address == null)
- throw new ArgumentNullException();
- return GetHostByAddress(CreateAddress(address));
- }
-
- [DllImport("cygwin1", EntryPoint="gethostbyname")]
- private static extern IntPtr _GetHostByName(string hostName);
- [MonoTODO]
- public static IPHostEntry GetHostByName(string hostName) {
- if (hostName == null)
- throw new ArgumentNullException();
- IntPtr p = _GetHostByName(hostName);
- // int errNo = _h_errno;
- if (p == IntPtr.Zero)
- throw new SocketException(); // TODO: set error code
- Hostent h = new Hostent();
- System.Runtime.InteropServices.Marshal.PtrToStructure(p, h);
- return ToIPHostEntry(h);
- }
-
- /// <summary>
- /// This method returns the host name associated with the local host.
- /// </summary>
- public static string GetHostName() {
- IPHostEntry h = GetHostByAddress("127.0.0.1");
- return h.HostName;
- }
-
- /// <summary>
- /// This method resovles a DNS-style host name or IP
- /// address.
- /// </summary>
- /// <param name=hostName>
- /// A string containing either a DNS-style host name (e.g.
- /// www.go-mono.com) or IP address (e.g. 129.250.184.233).
- /// </param>
- public static IPHostEntry Resolve(string hostName) {
- if (hostName == null)
- throw new ArgumentNullException();
- try {
- long addr = CreateAddress(hostName);
- if (addr > uint.MaxValue)
- throw new FormatException("Only IP version 4 addresses are supported");
- return GetHostByAddress(addr);
- } catch (FormatException) {
- return GetHostByName(hostName);
- }
- }
-
- /// <summary>
- /// Utility method. This method converts a Hostent instance to a
- /// IPHostEntry instance.
- /// </summary>
- /// <param name=h>
- /// Object which should be mapped to a IPHostEntry instance.
- /// </param>
- private static unsafe IPHostEntry ToIPHostEntry(Hostent h) {
- IPHostEntry res = new IPHostEntry();
-
- // Set host name
- res.HostName = h.h_name;
-
- // Set IP address list
- byte** p = h.h_addr_list;
- ArrayList tmp = new ArrayList(1);
- while (*p != null) {
- tmp.Add(CreateIPAddress(*p, h.h_length));
- ++p;
- }
- IPAddress[] addr_list = new IPAddress[tmp.Count];
- for(int i = 0; i < tmp.Count; ++i)
- addr_list[i] = (IPAddress)tmp[i];
- res.AddressList = addr_list;
-
- // Set IP aliases
- p = h.h_aliases;
- tmp.Clear();
- while (*p != null) {
- tmp.Add(new string((sbyte*)*p));
- ++p;
- }
- string[] aliases = new string[tmp.Count];
- for(int i = 0; i < tmp.Count; ++i)
- aliases[i] = (string)tmp[i];
- res.Aliases = aliases;
-
- return res;
- }
-
- /// <summary>
- /// Utility method. Convert IP address in dotted notation
- /// to IP address.
- /// </summary>
- private static long CreateAddress(string address) {
- string[] tokens = address.Split('.');
- if (tokens.Length % 4 != 0)
- throw new FormatException("IP address has invalid length");
- long addr = 0;
- for(int i = 0, j = tokens.Length - 1; i < tokens.Length; ++i, --j) {
- try {
- addr = addr | (((long)byte.Parse(tokens[i])) << j * 8);
- } catch (OverflowException) {
- throw new FormatException("Invalid IP address format");
- }
- }
- return addr;
- }
-
- /// <summary>
- /// Utility method. This method creates a IP address.
- /// </summary>
- /// <param name=addr>
- /// IP address in network byte order (e.g. Big-Endian).
- /// </param>
- /// <param name=length>
- /// Length of IP address (4 or 8 bytes).
- /// </param>
- private static unsafe IPAddress CreateIPAddress(byte* addr, short length) {
- byte* p = addr;
- long res = 0;
- for(int i = 0, j = length - 1; i < length; ++i, --j) {
- res += *p << j * 8;
- ++p;
- }
- if (res > uint.MaxValue)
- return new IPAddress(IPAddress.NetworkToHostOrder((long)res));
- else
- return new IPAddress(IPAddress.NetworkToHostOrder((int)res));
- }
- }
- }
|