--- /dev/null
+//
+// Mono.Dns.DnsClass
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsClass : ushort {
+ Internet = 1,
+ IN = 1,
+ CSNET = 2,
+ CS = 2,
+ CHAOS = 3,
+ CH = 3,
+ Hesiod = 4,
+ HS = 4,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsHeader
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsHeader {
+ public const int DnsHeaderLength = 12;
+ ArraySegment<byte> bytes;
+
+ public DnsHeader (byte [] bytes)
+ : this (bytes, 0)
+ {
+ }
+
+ public DnsHeader (byte [] bytes, int offset)
+ : this (new ArraySegment<byte> (bytes, offset, DnsHeaderLength))
+ {
+ }
+
+ public DnsHeader (ArraySegment<byte> segment)
+ {
+ if (segment.Count != DnsHeaderLength)
+ throw new ArgumentException ("Count must be 12", "segment");
+
+ bytes = segment;
+ }
+
+ public void Clear ()
+ {
+ for (int i = 0; i < DnsHeaderLength; i++)
+ bytes.Array [i + bytes.Offset] = 0;
+ }
+
+ public ushort ID {
+ get {
+ return (ushort)(bytes.Array [bytes.Offset] * 256 + bytes.Array [bytes.Offset + 1]);
+ }
+ set {
+ bytes.Array [bytes.Offset] = (byte) ((value & 0x0ff00) >> 8);
+ bytes.Array [bytes.Offset + 1] = (byte) (value & 0x0ff);
+ }
+ }
+
+ public bool IsQuery {
+ get { return ((bytes.Array [2 + bytes.Offset] & 0x80) != 0); }
+ set {
+ if (!value) {
+ bytes.Array [2 + bytes.Offset] |= 0x80;
+ } else {
+ bytes.Array [2 + bytes.Offset] &= 0x7f;
+ }
+ }
+ }
+
+ public DnsOpCode OpCode {
+ get { return (DnsOpCode) ((bytes.Array [2 + bytes.Offset] & 0x78) >> 3); }
+ set {
+ if (!Enum.IsDefined (typeof (DnsOpCode), value))
+ throw new ArgumentOutOfRangeException ("value", "Invalid DnsOpCode value");
+
+ int v = (int) value;
+ v <<= 3;
+ int prev = (bytes.Array [2 + bytes.Offset] & 0x87);
+ v |= prev;
+ bytes.Array [2 + bytes.Offset] = (byte) v;
+ }
+ }
+
+ public bool AuthoritativeAnswer {
+ get { return (bytes.Array [2 + bytes.Offset] & 4) != 0; }
+ set {
+ if(value) {
+ bytes.Array [2 + bytes.Offset] |= 4;
+ } else {
+ bytes.Array [2 + bytes.Offset] &= 0xFB;
+ }
+ }
+ }
+
+ public bool Truncation {
+ get { return (bytes.Array [2 + bytes.Offset] & 2) != 0; }
+ set {
+ if(value) {
+ bytes.Array [2 + bytes.Offset] |= 2;
+ } else {
+ bytes.Array [2 + bytes.Offset] &= 0xFD;
+ }
+ }
+ }
+
+ public bool RecursionDesired {
+ get { return (bytes.Array [2 + bytes.Offset] & 1) != 0; }
+ set {
+ if(value) {
+ bytes.Array [2 + bytes.Offset] |= 1;
+ } else {
+ bytes.Array [2 + bytes.Offset] &= 0xFE;
+ }
+ }
+ }
+
+ public bool RecursionAvailable {
+ get { return (bytes.Array [3 + bytes.Offset] & 0x80) != 0; }
+ set {
+ if(value) {
+ bytes.Array [3 + bytes.Offset] |= 0x80;
+ } else {
+ bytes.Array [3 + bytes.Offset] &= 0x7F;
+ }
+ }
+ }
+
+ // TODO: Add AuthenticData and Checking Disabled (bit 10 and 11 of Z)
+ public int ZReserved {
+ get { return (bytes.Array [3 + bytes.Offset] & 0x70) >> 4; }
+ set {
+ if(value < 0 || value > 7) {
+ throw new ArgumentOutOfRangeException("value", "Must be between 0 and 7");
+ }
+ bytes.Array [3 + bytes.Offset] &= 0x8F;
+ bytes.Array [3 + bytes.Offset] |= (byte) ((value << 4) & 0x70);
+ }
+ }
+
+ public DnsRCode RCode {
+ get { return (DnsRCode) (bytes.Array [3 + bytes.Offset] & 0x0f); }
+ set {
+ int v = (int)value;
+ //Info: Values > 15 are encoded in other records (OPT, TSIG, TKEY)
+ if (v < 0 || v > 15)
+ throw new ArgumentOutOfRangeException("value", "Must be between 0 and 15");
+
+ bytes.Array [3 + bytes.Offset] &= 0x0f;
+ bytes.Array [3 + bytes.Offset] |= (byte) v;
+ }
+ }
+
+ static ushort GetUInt16 (byte [] bytes, int offset)
+ {
+ return (ushort)(bytes [offset] * 256 + bytes [offset + 1]);
+ }
+
+ static void SetUInt16 (byte [] bytes, int offset, ushort val)
+ {
+ bytes [offset] = (byte) ((val & 0x0ff00) >> 8);
+ bytes [offset + 1] = (byte) (val & 0x0ff);
+ }
+
+ public ushort QuestionCount {
+ get { return GetUInt16 (bytes.Array, 4); }
+ set { SetUInt16 (bytes.Array, 4, value); }
+ }
+
+ public ushort AnswerCount {
+ get { return GetUInt16 (bytes.Array, 6); }
+ set { SetUInt16 (bytes.Array, 6, value); }
+ }
+
+ public ushort AuthorityCount {
+ get { return GetUInt16 (bytes.Array, 8); }
+ set { SetUInt16 (bytes.Array, 8, value); }
+ }
+
+ public ushort AdditionalCount {
+ get { return GetUInt16 (bytes.Array, 10); }
+ set { SetUInt16 (bytes.Array, 10, value); }
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendFormat ("ID: {0} QR: {1} Opcode: {2} AA: {3} TC: {4} RD: {5} RA: {6} \r\nRCode: {7} ",
+ ID, IsQuery, OpCode, AuthoritativeAnswer, Truncation, RecursionDesired,
+ RecursionAvailable, RCode);
+ sb.AppendFormat ("Q: {0} A: {1} NS: {2} AR: {3}\r\n", QuestionCount, AnswerCount, AuthorityCount, AdditionalCount);
+ return sb.ToString();
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsOpCode
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsOpCode : byte {
+ Query = 0,
+ [Obsolete] IQuery = 1,
+ Status = 2,
+ Notify = 4,
+ Update = 5,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsPacket
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ abstract class DnsPacket {
+ protected byte [] packet;
+ protected int position;
+ protected DnsHeader header;
+
+ protected DnsPacket ()
+ {
+ // Caller has to initialize packet, position and header
+ }
+
+ protected DnsPacket (int length)
+ : this (new byte [length], length)
+ {
+ }
+
+ protected DnsPacket (byte [] buffer, int length)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+ if (length <= 0)
+ throw new ArgumentOutOfRangeException("length", "Must be greater than zero.");
+
+ packet = buffer;
+ position = length;
+ header = new DnsHeader(new ArraySegment<byte>(packet, 0, 12));
+ }
+
+ public byte [] Packet {
+ get { return packet; }
+ }
+
+ public int Length {
+ get { return position; }
+ }
+
+ public DnsHeader Header {
+ get { return header; }
+ }
+
+ protected void WriteUInt16 (ushort v)
+ {
+ packet [position++] = (byte) ((v & 0x0ff00) >> 8);
+ packet [position++] = (byte) (v & 0x0ff);
+ }
+
+ protected void WriteStringBytes (string str, int offset, int count)
+ {
+ for (int i = offset, c = 0; c < count; c++, i++)
+ packet [position++] = (byte) str [i]; // Don't care about encoding.
+ }
+
+ protected void WriteLabel (string str, int offset, int count)
+ {
+ packet [position++] = (byte) count;
+ WriteStringBytes (str, offset, count);
+ }
+
+ protected void WriteDnsName (string name)
+ {
+ if (!DnsUtil.IsValidDnsName (name))
+ throw new ArgumentException ("Invalid DNS name");
+
+ if (!String.IsNullOrEmpty (name)) {
+ int len = name.Length;
+ int label_start = 0;
+ int label_len = 0;
+ for (int i = 0; i < len; i++) {
+ char c = name [i];
+ if (c != '.') {
+ label_len++;
+ } else {
+ if (i == 0)
+ break; // "."
+ WriteLabel (name, label_start, label_len);
+ label_start += label_len + 1; // Skip the dot
+ label_len = 0;
+ }
+ }
+ if (label_len > 0)
+ WriteLabel (name, label_start, label_len);
+ }
+
+ packet [position++] = 0;
+ }
+
+ protected internal string ReadName (ref int offset)
+ {
+ return DnsUtil.ReadName (packet, ref offset);
+ }
+
+ protected internal static string ReadName (byte [] buffer, ref int offset)
+ {
+ return DnsUtil.ReadName (buffer, ref offset);
+ }
+
+ protected internal ushort ReadUInt16 (ref int offset)
+ {
+ return (ushort)((packet[offset++] << 8) + packet[offset++]);
+ }
+
+ protected internal int ReadInt32 (ref int offset)
+ {
+ return (packet [offset++] << 24) + (packet [offset++] << 16) + (packet [offset++] << 8) + packet [offset++];
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsQClass
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsQClass : ushort {
+ Internet = 1,
+ IN = 1,
+ CSNET = 2,
+ CS = 2,
+ CHAOS = 3,
+ CH = 3,
+ Hesiod = 4,
+ HS = 4,
+ None = 254,
+ Any = 255
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsQType
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsQType : ushort {
+ A = 1,
+ NS = 2,
+ [Obsolete] MD = 3,
+ [Obsolete] MF = 4,
+ CNAME = 5,
+ SOA = 6,
+ [Obsolete] MB = 7,
+ [Obsolete] MG = 8,
+ [Obsolete] MR = 9,
+ [Obsolete] NULL = 10,
+ [Obsolete] WKS = 11,
+ PTR = 12,
+ [Obsolete] HINFO = 13,
+ [Obsolete] MINFO = 14,
+ MX = 15,
+ TXT = 16,
+ [Obsolete] RP = 17,
+ AFSDB = 18,
+ [Obsolete] X25 = 19,
+ [Obsolete] ISDN = 20,
+ [Obsolete] RT = 21,
+ [Obsolete] NSAP = 22,
+ [Obsolete] NSAPPTR = 23,
+ SIG = 24,
+ KEY = 25,
+ [Obsolete] PX = 26,
+ [Obsolete] GPOS = 27,
+ AAAA = 28,
+ LOC = 29,
+ [Obsolete] NXT = 30,
+ [Obsolete] EID = 31,
+ [Obsolete] NIMLOC = 32,
+ SRV = 33,
+ [Obsolete] ATMA = 34,
+ NAPTR = 35,
+ KX = 36,
+ CERT = 37,
+ [Obsolete] A6 = 38,
+ DNAME = 39,
+ [Obsolete] SINK = 40,
+ OPT = 41,
+ [Obsolete] APL = 42,
+ DS = 43,
+ SSHFP = 44,
+ IPSECKEY = 45,
+ RRSIG = 46,
+ NSEC = 47,
+ DNSKEY = 48,
+ DHCID = 49,
+ NSEC3 = 50,
+ NSEC3PARAM = 51,
+ HIP = 55,
+ NINFO = 56,
+ RKEY = 57,
+ TALINK = 58,
+ SPF = 99,
+ [Obsolete] UINFO = 100,
+ [Obsolete] UID = 101,
+ [Obsolete] GID = 102,
+ [Obsolete] UNSPEC = 103,
+ TKEY = 249,
+ TSIG = 250,
+ IXFR = 251,
+ AXFR = 252,
+ [Obsolete] MAILB = 253,
+ [Obsolete] MAILA = 254,
+ ALL = 255,
+ URI = 256,
+ TA = 32768,
+ DLV = 32769,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsQuery
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsQuery : DnsPacket {
+ public DnsQuery (string name, DnsQType qtype, DnsQClass qclass)
+ {
+ if (String.IsNullOrEmpty (name))
+ throw new ArgumentNullException ("name");
+
+ int length = DnsUtil.GetEncodedLength (name);
+ if (length == -1)
+ throw new ArgumentException ("Invalid DNS name", "name");
+
+ length += 12 + 2 + 2; // Header + qtype + qclass
+ packet = new byte [length];
+ header = new DnsHeader (packet, 0);
+ position = 12;
+ WriteDnsName (name);
+ WriteUInt16 ((ushort) qtype);
+ WriteUInt16 ((ushort) qclass);
+ Header.QuestionCount = 1;
+ Header.IsQuery = true;
+ Header.RecursionDesired = true;
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsQuestion
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsQuestion {
+ string name;
+ DnsQType type;
+ DnsQClass _class;
+
+ internal DnsQuestion ()
+ {
+ }
+
+ internal int Init (DnsPacket packet, int offset)
+ {
+ name = packet.ReadName (ref offset);
+ type = (DnsQType) packet.ReadUInt16 (ref offset);
+ _class = (DnsQClass) packet.ReadUInt16 (ref offset);
+ return offset;
+ }
+
+ public string Name {
+ get { return name; }
+ }
+
+ public DnsQType Type {
+ get { return type; }
+ }
+
+ public DnsQClass Class {
+ get { return _class; }
+ }
+
+ public override string ToString() {
+ return String.Format("Name: {0} Type: {1} Class: {2}", Name, Type, Class);
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsRCode
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsRCode : ushort {
+ NoError = 0,
+ FormErr = 1,
+ ServFail = 2,
+ NXDomain = 3,
+ NotImp = 4,
+ Refused = 5,
+ YXDomain = 6,
+ YXRRSet = 7,
+ NXRRSet = 8,
+ NotAuth = 9,
+ NotZone = 10,
+ BadVers = 16,
+ BadSig = 16,
+ BadKey = 17,
+ BadTime = 18,
+ BadMode = 19,
+ BadName = 20,
+ BadAlg = 21,
+ BadTrunc = 22,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecord
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResourceRecord {
+ string name;
+ DnsType type;
+ DnsClass klass;
+ int ttl;
+ ushort rdlength;
+ ArraySegment<byte> m_rdata;
+
+ internal DnsResourceRecord() {
+ }
+
+ internal void CopyFrom(DnsResourceRecord rr) {
+ name = rr.name;
+ type = rr.type;
+ klass = rr.klass;
+ ttl = rr.ttl;
+ rdlength = rr.rdlength;
+ m_rdata = rr.m_rdata;
+ }
+
+ static internal DnsResourceRecord CreateFromBuffer(DnsPacket packet, int size, ref int offset) {
+ string pname = packet.ReadName(ref offset);
+ DnsType ptype = (DnsType)packet.ReadUInt16(ref offset);
+ DnsClass pclass = (DnsClass)packet.ReadUInt16(ref offset);
+ int pttl = packet.ReadInt32(ref offset);
+ ushort prdlength = packet.ReadUInt16(ref offset);
+ DnsResourceRecord rr = new DnsResourceRecord();
+ rr.name = pname;
+ rr.type = ptype;
+ rr.klass = pclass;
+ rr.ttl = pttl;
+ rr.rdlength = prdlength;
+ rr.m_rdata = new ArraySegment<byte>(packet.Packet, offset, prdlength);
+ offset += prdlength;
+
+ switch(pclass) {
+ case DnsClass.IN:
+ switch(ptype) {
+ case DnsType.A:
+ rr = new DnsResourceRecordA(rr);
+ break;
+ case DnsType.AAAA:
+ rr = new DnsResourceRecordAAAA(rr);
+ break;
+ case DnsType.CNAME:
+ rr = new DnsResourceRecordCName(rr);
+ break;
+ case DnsType.PTR:
+ rr = new DnsResourceRecordPTR(rr);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return rr;
+ }
+
+ public string Name {
+ get { return name; }
+ }
+
+ public DnsType Type {
+ get { return type; }
+ }
+
+ public DnsClass Class {
+ get { return klass; }
+ }
+
+ public int Ttl {
+ get { return ttl; }
+ }
+
+ public ArraySegment<byte> Data {
+ get { return m_rdata; }
+ }
+
+ public override string ToString() {
+ return String.Format("Name: {0}, Type: {1}, Class: {2}, Ttl: {3}, Data length: {4}", name, type, klass, ttl, Data.Count);
+ }
+ }
+}
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecordA
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResourceRecordA : DnsResourceRecordIPAddress {
+ internal DnsResourceRecordA (DnsResourceRecord rr)
+ : base (rr, 4)
+ {
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecordAAAA
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResourceRecordAAAA : DnsResourceRecordIPAddress {
+ internal DnsResourceRecordAAAA (DnsResourceRecord rr)
+ : base (rr, 16)
+ {
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecordCName
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResourceRecordCName : DnsResourceRecord {
+ string cname;
+
+ internal DnsResourceRecordCName (DnsResourceRecord rr)
+ {
+ CopyFrom (rr);
+ int offset = rr.Data.Offset;
+ cname = DnsPacket.ReadName (rr.Data.Array, ref offset);
+ }
+
+ public string CName {
+ get { return cname; }
+ }
+
+ public override string ToString ()
+ {
+ return base.ToString () + " CNAME: " + cname.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecordIPAddress
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ abstract class DnsResourceRecordIPAddress : DnsResourceRecord {
+ IPAddress address;
+
+ internal DnsResourceRecordIPAddress (DnsResourceRecord rr, int address_size)
+ {
+ CopyFrom (rr);
+ ArraySegment<byte> segment = rr.Data;
+ byte [] bytes = new byte [address_size];
+ Buffer.BlockCopy (segment.Array, segment.Offset, bytes, 0, address_size);
+ address = new IPAddress (bytes);
+ }
+
+ public override string ToString ()
+ {
+ return base.ToString() + " Address: " + address;
+ }
+
+ public IPAddress Address {
+ get { return address; }
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsResourceRecordPTR
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResourceRecordPTR : DnsResourceRecord {
+ string dname;
+
+ internal DnsResourceRecordPTR (DnsResourceRecord rr)
+ {
+ CopyFrom (rr);
+ int offset = rr.Data.Offset;
+ dname = DnsPacket.ReadName (rr.Data.Array, ref offset);
+ }
+
+ public string DName {
+ get { return dname; }
+ }
+
+ public override string ToString() {
+ return base.ToString () + " DNAME: " + dname.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// Mono.Dns.DnsResponse
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class DnsResponse : DnsPacket {
+ static readonly ReadOnlyCollection<DnsResourceRecord> EmptyRR = new ReadOnlyCollection<DnsResourceRecord> (new DnsResourceRecord [0]);
+ static readonly ReadOnlyCollection<DnsQuestion> EmptyQS = new ReadOnlyCollection<DnsQuestion> (new DnsQuestion [0]);
+
+ ReadOnlyCollection<DnsQuestion> question;
+ ReadOnlyCollection<DnsResourceRecord> answer;
+ ReadOnlyCollection<DnsResourceRecord> authority;
+ ReadOnlyCollection<DnsResourceRecord> additional;
+ int offset = DnsHeader.DnsHeaderLength;
+
+ public DnsResponse (byte [] buffer, int length)
+ : base (buffer, length)
+ {
+ }
+
+ public void Reset ()
+ {
+ question = null;
+ answer = null;
+ authority = null;
+ additional = null;
+ for (int i = 0; i < packet.Length; i++)
+ packet [i] = 0;
+ }
+
+ ReadOnlyCollection<DnsResourceRecord> GetRRs (int count)
+ {
+ if (count <= 0)
+ return EmptyRR;
+
+ List<DnsResourceRecord> records = new List<DnsResourceRecord>(count);
+ for (int i = 0; i < count; i++)
+ records.Add (DnsResourceRecord.CreateFromBuffer (this, position, ref offset));
+ return records.AsReadOnly ();
+ }
+
+ ReadOnlyCollection<DnsQuestion> GetQuestions (int count)
+ {
+ if (count <= 0)
+ return EmptyQS;
+
+ List<DnsQuestion> records = new List<DnsQuestion> (count);
+ for(int i = 0; i < count; i++) {
+ DnsQuestion record = new DnsQuestion ();
+ offset = record.Init (this, offset);
+ records.Add (record);
+ }
+ return records.AsReadOnly ();
+ }
+
+ public ReadOnlyCollection<DnsQuestion> GetQuestions ()
+ {
+ if (question == null)
+ question = GetQuestions (Header.QuestionCount);
+ return question;
+ }
+
+ public ReadOnlyCollection<DnsResourceRecord> GetAnswers ()
+ {
+ if (answer == null) {
+ GetQuestions ();
+ answer = GetRRs (Header.AnswerCount);
+ }
+ return answer;
+ }
+
+ public ReadOnlyCollection<DnsResourceRecord> GetAuthority ()
+ {
+ if (authority == null) {
+ GetQuestions ();
+ GetAnswers ();
+ authority = GetRRs (Header.AuthorityCount);
+ }
+ return authority;
+ }
+
+ public ReadOnlyCollection<DnsResourceRecord> GetAdditional ()
+ {
+ if (additional == null) {
+ GetQuestions ();
+ GetAnswers ();
+ GetAuthority ();
+ additional = GetRRs (Header.AdditionalCount);
+ }
+ return additional;
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(Header);
+ sb.Append("Question:\r\n");
+ foreach(DnsQuestion q in GetQuestions()) {
+ sb.AppendFormat("\t{0}\r\n", q);
+ }
+ sb.Append("Answer(s):\r\n");
+ foreach(DnsResourceRecord q in GetAnswers()) {
+ sb.AppendFormat("\t{0}\r\n", q);
+ }
+ sb.Append("Authority:\r\n");
+ foreach(DnsResourceRecord q in GetAuthority()) {
+ sb.AppendFormat("\t{0}\r\n", q);
+ }
+ sb.Append("Additional:\r\n");
+ foreach(DnsResourceRecord q in GetAdditional()) {
+ sb.AppendFormat("\t{0}\r\n", q);
+ }
+ return sb.ToString();
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsType
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum DnsType : ushort {
+ A = 1,
+ NS = 2,
+ [Obsolete] MD = 3,
+ [Obsolete] MF = 4,
+ CNAME = 5,
+ SOA = 6,
+ [Obsolete] MB = 7,
+ [Obsolete] MG = 8,
+ [Obsolete] MR = 9,
+ [Obsolete] NULL = 10,
+ [Obsolete] WKS = 11,
+ PTR = 12,
+ [Obsolete] HINFO = 13,
+ [Obsolete] MINFO = 14,
+ MX = 15,
+ TXT = 16,
+ [Obsolete] RP = 17,
+ AFSDB = 18,
+ [Obsolete] X25 = 19,
+ [Obsolete] ISDN = 20,
+ [Obsolete] RT = 21,
+ [Obsolete] NSAP = 22,
+ [Obsolete] NSAPPTR = 23,
+ SIG = 24,
+ KEY = 25,
+ [Obsolete] PX = 26,
+ [Obsolete] GPOS = 27,
+ AAAA = 28,
+ LOC = 29,
+ [Obsolete] NXT = 30,
+ [Obsolete] EID = 31,
+ [Obsolete] NIMLOC = 32,
+ SRV = 33,
+ [Obsolete] ATMA = 34,
+ NAPTR = 35,
+ KX = 36,
+ CERT = 37,
+ [Obsolete] A6 = 38,
+ DNAME = 39,
+ [Obsolete] SINK = 40,
+ OPT = 41,
+ [Obsolete] APL = 42,
+ DS = 43,
+ SSHFP = 44,
+ IPSECKEY = 45,
+ RRSIG = 46,
+ NSEC = 47,
+ DNSKEY = 48,
+ DHCID = 49,
+ NSEC3 = 50,
+ NSEC3PARAM = 51,
+ HIP = 55,
+ NINFO = 56,
+ RKEY = 57,
+ TALINK = 58,
+ SPF = 99,
+ [Obsolete] UINFO = 100,
+ [Obsolete] UID = 101,
+ [Obsolete] GID = 102,
+ [Obsolete] UNSPEC = 103,
+ TKEY = 249,
+ TSIG = 250,
+ IXFR = 251,
+ AXFR = 252,
+ [Obsolete] MAILB = 253,
+ [Obsolete] MAILA = 254,
+ URI = 256,
+ TA = 32768,
+ DLV = 32769,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.DnsUtil
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ static class DnsUtil {
+ // RFC 2181 - Section 11
+ public static bool IsValidDnsName (string name)
+ {
+ if (name == null)
+ return false;
+
+ int len = name.Length;
+ if (len > 255)
+ return false;
+ int part_length = 0;
+ for (int i = 0; i < len; i++) {
+ char c = name [i];
+ if (c == '.') {
+ if (i == 0 && len > 1)
+ return false; // Can't begin with a dot unless it's "."
+ if (i > 0 && part_length == 0)
+ return false; // No ".." allowed
+ part_length = 0;
+ continue;
+ }
+ part_length++;
+ if (part_length > 63)
+ return false;
+ }
+ return true;
+ }
+
+ public static int GetEncodedLength (string name)
+ {
+ if (!IsValidDnsName (name))
+ return -1;
+
+ if (name == String.Empty)
+ return 1;
+
+ int len = name.Length;
+ if (name [len - 1] == '.')
+ return len + 1; // (length + label + ... + \0)
+ return len + 2; // need 1 more for the second to last label length
+ }
+
+ public static int GetNameLength (byte [] buffer)
+ {
+ return GetNameLength (buffer, 0);
+ }
+
+ public static int GetNameLength (byte [] buffer, int offset)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+ if (offset < 0 || offset >= buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ int i = 0;
+ int len = 0;
+ while (len < 256) {
+ i = buffer [offset++];
+ if (i == 0)
+ return len > 0 ? --len : 0;
+ int ptr = i & 0x0C0;
+ if (ptr == 0x0C0) {
+ i = ((ptr & 0x3F) << 8) + buffer[offset++];
+ offset = i;
+ continue;
+ } else if (ptr >= 0x40) {
+ return -2; // Invalid ptr
+ }
+ len += i + 1;
+ offset += i;
+ }
+ return -1; // Invalid length
+ }
+
+ public static string ReadName (byte [] buffer, ref int offset)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+ if (offset < 0 || offset >= buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ StringBuilder sb = new StringBuilder (32);
+ int i = 0;
+ bool no_ptr = true;
+ int off = offset;
+ while (sb.Length < 256) {
+ i = buffer [off++];
+ if (no_ptr) offset++;
+ if (i == 0) {
+ if (sb.Length > 0)
+ sb.Length--;
+ return sb.ToString ();
+ }
+ int ptr = i & 0x0C0;
+ if (ptr == 0x0C0) {
+ i = ((ptr & 0x3F) << 8) + buffer [off];
+ if (no_ptr) offset++;
+ no_ptr = false;
+ off = i;
+ continue;
+ } else if (i >= 0x40) {
+ return null; // Invalid ptr
+ }
+
+ for (int k = 0; k < i; k++)
+ sb.Append ((char) buffer [off + k]);
+ sb.Append ('.');
+ off += i;
+ if (no_ptr) offset += i;
+ }
+ return null; // never reached
+ }
+
+ }
+}
+
--- /dev/null
+SOURCES= \
+ DnsClass.cs \
+ DnsHeader.cs \
+ DnsPacket.cs \
+ DnsQClass.cs \
+ DnsQType.cs \
+ DnsQuery.cs \
+ DnsQuestion.cs \
+ DnsResourceRecordA.cs \
+ DnsResourceRecordCName.cs \
+ DnsResourceRecordPTR.cs \
+ DnsResourceRecord.cs \
+ DnsResponse.cs \
+ DnsType.cs \
+ ResolverAsyncOperation.cs \
+ Resolver.cs \
+ ResolverError.cs \
+ SimpleResolverEventArgs.cs
+
+EXES = resolver.exe \
+ plainolddns.exe
+
+all: $(EXES)
+
+resolver.exe: $(SOURCES)
+ @gmcs -out:$@ -debug $(SOURCES)
+
+plainolddns.exe: plainolddns.cs
+ @gmcs -out:$@ -debug $^
+clean:
+ rm -f resolver.exe* plainolddns.exe* *.mdb
--- /dev/null
+//
+// Mono.Dns.ResolverAsyncOperation
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum ResolverAsyncOperation {
+ None,
+ GetHostEntry,
+ GetHostAddresses,
+ }
+}
+
--- /dev/null
+// Mono.Dns.ResolverError
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ enum ResolverError {
+ NoError, // From DNS server
+ FormatError, //
+ ServerFailure, //
+ NameError, //
+ NotImplemented, //
+ Refused, //
+ // Resolver specific
+ ResponseHeaderError,
+ ResponseFormatError,
+ Timeout,
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.SimpleResolver
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ sealed class SimpleResolver : IDisposable {
+ static string [] EmptyStrings = new string [0];
+ static IPAddress [] EmptyAddresses = new IPAddress [0];
+ IPEndPoint [] endpoints;
+ Socket client;
+ Dictionary<int, SimpleResolverEventArgs> queries;
+ AsyncCallback receive_cb;
+ TimerCallback timeout_cb;
+ bool disposed;
+#if REUSE_RESPONSES
+ Stack<DnsResponse> responses_avail = new Stack<DnsResponse> ();
+#endif
+
+ public SimpleResolver ()
+ {
+ queries = new Dictionary<int, SimpleResolverEventArgs> ();
+ receive_cb = new AsyncCallback (OnReceive);
+ timeout_cb = new TimerCallback (OnTimeout);
+ InitFromSystem ();
+ InitSocket ();
+ }
+
+ void IDisposable.Dispose ()
+ {
+ if (!disposed) {
+ disposed = true;
+ if (client != null) {
+ client.Close ();
+ client = null;
+ }
+ }
+ }
+
+ public void Close ()
+ {
+ ((IDisposable) this).Dispose ();
+ }
+
+ void GetLocalHost (SimpleResolverEventArgs args)
+ {
+ //FIXME
+ IPHostEntry entry = new IPHostEntry ();
+ entry.HostName = "localhost";
+ entry.AddressList = new IPAddress [] { IPAddress.Loopback };
+ entry.Aliases = EmptyStrings;
+ args.ResolverError = 0;
+ args.HostEntry = entry;
+ return;
+
+/*
+ List<IPEndPoint> eps = new List<IPEndPoint> ();
+ foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces ()) {
+ if (NetworkInterfaceType.Loopback == iface.NetworkInterfaceType)
+ continue;
+
+ foreach (IPAddress addr in iface.GetIPProperties ().DnsAddresses) {
+ if (AddressFamily.InterNetworkV6 == addr.AddressFamily)
+ continue;
+ IPEndPoint ep = new IPEndPoint (addr, 53);
+ if (eps.Contains (ep))
+ continue;
+
+ eps.Add (ep);
+ }
+ }
+ endpoints = eps.ToArray ();
+*/
+ }
+
+ // Type A query
+ // Might fill in Aliases
+ // -IPAddress -> return the same IPAddress
+ // -"" -> Local host ip addresses (filter out IPv6 if needed)
+ public bool GetHostAddressesAsync (SimpleResolverEventArgs args)
+ {
+ if (args == null)
+ throw new ArgumentNullException ("args");
+
+ if (args.HostName == null)
+ throw new ArgumentNullException ("args.HostName is null");
+
+ if (args.HostName.Length > 255)
+ throw new ArgumentException ("args.HostName is too long");
+
+ args.Reset (ResolverAsyncOperation.GetHostAddresses);
+ string host = args.HostName;
+ if (host == "") {
+ GetLocalHost (args);
+ return false;
+ }
+ IPAddress addr;
+ if (IPAddress.TryParse (host, out addr)) {
+ IPHostEntry entry = new IPHostEntry ();
+ entry.HostName = host;
+ entry.Aliases = EmptyStrings;
+ entry.AddressList = new IPAddress [1] { addr };
+ args.HostEntry = entry;
+ return false;
+ }
+
+ SendAQuery (args, true);
+ return true;
+ }
+
+ // For names -> type A Query
+ // For IP addresses -> PTR + A -> will at least return itself
+ // Careful: for IP addresses with PTR, the hostname might yield different IP addresses!
+ public bool GetHostEntryAsync (SimpleResolverEventArgs args)
+ {
+ if (args == null)
+ throw new ArgumentNullException ("args");
+
+ if (args.HostName == null)
+ throw new ArgumentNullException ("args.HostName is null");
+
+ if (args.HostName.Length > 255)
+ throw new ArgumentException ("args.HostName is too long");
+
+ args.Reset (ResolverAsyncOperation.GetHostEntry);
+ string host = args.HostName;
+ if (host == "") {
+ GetLocalHost (args);
+ return false;
+ }
+
+ IPAddress addr;
+ if (IPAddress.TryParse (host, out addr)) {
+ IPHostEntry entry = new IPHostEntry ();
+ entry.HostName = host;
+ entry.Aliases = EmptyStrings;
+ entry.AddressList = new IPAddress [1] { addr };
+ args.HostEntry = entry;
+ args.PTRAddress = addr;
+ SendPTRQuery (args, true);
+ return true;
+ }
+
+ // 3. For IP addresses:
+ // 3.1 Parsing IP succeeds
+ // 3.2 Reverse lookup of the IP fills in HostName -> fails? HostName = IP
+ // 3.3 The hostname resulting from this is used to query DNS again to get the IP addresses
+ //
+ // Exclude IPv6 addresses if not supported by the system
+ // .Aliases is always empty
+ // Length > 255
+ SendAQuery (args, true);
+ return true;
+ }
+
+ bool AddQuery (DnsQuery query, SimpleResolverEventArgs args)
+ {
+ lock (queries) {
+ if (queries.ContainsKey (query.Header.ID))
+ return false;
+ queries [query.Header.ID] = args;
+ }
+ return true;
+ }
+
+ static DnsQuery GetQuery (string host, DnsQType q, DnsQClass c)
+ {
+ return new DnsQuery (host, q, c);
+ }
+
+ void SendAQuery (SimpleResolverEventArgs args, bool add_it)
+ {
+ SendAQuery (args, args.HostName, add_it);
+ }
+
+ void SendAQuery (SimpleResolverEventArgs args, string host, bool add_it)
+ {
+ DnsQuery query = GetQuery (host, DnsQType.A, DnsQClass.IN);
+ SendQuery (args, query, add_it);
+ }
+
+ static string GetPTRName (IPAddress address)
+ {
+ // TODO: IPv6 PTR query?
+ byte [] bytes = address.GetAddressBytes ();
+ // "XXX.XXX.XXX.XXX.in-addr.arpa".Length
+ StringBuilder sb = new StringBuilder (28);
+ for (int i = bytes.Length - 1; i >= 0; i--) {
+ sb.AppendFormat ("{0}.", bytes [i]);
+ }
+ sb.Append ("in-addr.arpa");
+ return sb.ToString ();
+ }
+
+ void SendPTRQuery (SimpleResolverEventArgs args, bool add_it)
+ {
+ DnsQuery query = GetQuery (GetPTRName (args.PTRAddress), DnsQType.PTR, DnsQClass.IN);
+ SendQuery (args, query, add_it);
+ }
+
+ void SendQuery (SimpleResolverEventArgs args, DnsQuery query, bool add_it)
+ {
+ // TODO: not sure about reusing IDs when add_it == false
+ int count = 0;
+ if (add_it) {
+ do {
+ query.Header.ID = (ushort)new Random().Next(1, 65534);
+ if (count > 500)
+ throw new InvalidOperationException ("Too many pending queries (or really bad luck)");
+ } while (AddQuery (query, args) == false);
+ args.QueryID = query.Header.ID;
+ } else {
+ query.Header.ID = args.QueryID;
+ }
+ if (args.Timer == null)
+ args.Timer = new Timer (timeout_cb, args, 5000, Timeout.Infinite);
+ else
+ args.Timer.Change (5000, Timeout.Infinite);
+ client.BeginSend (query.Packet, 0, query.Length, SocketFlags.None, null, null);
+ }
+
+ byte [] GetFreshBuffer ()
+ {
+#if !REUSE_RESPONSES
+ return new byte [512];
+#else
+
+ DnsResponse response = null;
+ lock (responses_avail) {
+ if (responses_avail.Count > 0) {
+ response = responses_avail.Pop ();
+ }
+ }
+ if (response == null) {
+ response = new DnsResponse ();
+ } else {
+ response.Reset ();
+ }
+ return response;
+#endif
+ }
+
+ void FreeBuffer (byte [] buffer)
+ {
+#if REUSE_RESPONSES
+ // TODO: set some limit here. Configurable?
+ lock (responses_avail) {
+ responses_avail.Push (response);
+ }
+#endif
+ }
+
+ void InitSocket ()
+ {
+ client = new Socket (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ client.Blocking = true;
+ client.Bind (new IPEndPoint (IPAddress.Any, 0));
+ client.Connect (endpoints [0]);
+ BeginReceive ();
+ }
+
+ void BeginReceive ()
+ {
+ byte [] buffer = GetFreshBuffer ();
+ client.BeginReceive (buffer, 0, buffer.Length, SocketFlags.None, receive_cb, buffer);
+ }
+
+ void OnTimeout (object obj)
+ {
+ SimpleResolverEventArgs args = (SimpleResolverEventArgs) obj;
+ SimpleResolverEventArgs args2;
+ lock (queries) {
+ if (!queries.TryGetValue (args.QueryID, out args2)) {
+ return; // Already processed.
+ }
+ if (args != args2)
+ throw new Exception ("Should not happen: args != args2");
+ args.Retries++;
+ if (args.Retries > 1) {
+ // Error timeout
+ args.ResolverError = ResolverError.Timeout;
+ args.OnCompleted (this);
+ } else {
+ SendAQuery (args, false);
+ }
+ }
+ }
+
+ void OnReceive (IAsyncResult ares)
+ {
+ if (disposed)
+ return;
+
+ int nread = 0;
+ EndPoint remote_ep = client.RemoteEndPoint;
+ try {
+ nread = client.EndReceive (ares);
+ } catch (Exception e) {
+ Console.Error.WriteLine (e);
+ }
+
+ BeginReceive ();
+
+ byte [] buffer = (byte []) ares.AsyncState;
+ if (nread > 12) {
+ DnsResponse response = new DnsResponse (buffer, nread);
+ int id = response.Header.ID;
+ SimpleResolverEventArgs args = null;
+ lock (queries) {
+ if (queries.TryGetValue (id, out args)) {
+ queries.Remove (id);
+ }
+ }
+
+ if (args != null) {
+ Timer t = args.Timer;
+ if (t != null)
+ t.Change (Timeout.Infinite, Timeout.Infinite);
+
+ try {
+ ProcessResponse (args, response, remote_ep);
+ } catch (Exception e) {
+ args.ResolverError = (ResolverError) (-1);
+ args.ErrorMessage = e.Message;
+ }
+
+ IPHostEntry entry = args.HostEntry;
+ if (args.ResolverError != 0 && args.PTRAddress != null && entry != null && entry.HostName != null) {
+ args.PTRAddress = null;
+ SendAQuery (args, entry.HostName, true);
+ args.Timer.Change (5000, Timeout.Infinite);
+ } else {
+ args.OnCompleted (this);
+ }
+ }
+ }
+ FreeBuffer (buffer);
+ }
+
+ void ProcessResponse (SimpleResolverEventArgs args, DnsResponse response, EndPoint server_ep)
+ {
+ DnsRCode status = response.Header.RCode;
+ if (status != 0) {
+ if (args.PTRAddress != null) {
+ // PTR query failed -> no error, we have the IP
+ return;
+ }
+ args.ResolverError = (ResolverError) status;
+ return;
+ }
+
+ // TODO: verify IP of the server is in our list and the same one that got the query
+ IPEndPoint ep = (IPEndPoint) server_ep;
+ if (ep.Port != 53) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "Port";
+ return;
+ }
+
+ DnsHeader header = response.Header;
+ if (!header.IsQuery) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "IsQuery";
+ return;
+ }
+
+ // TODO: handle Truncation. Retry with bigger buffer?
+
+ if (header.QuestionCount > 1) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "QuestionCount";
+ return;
+ }
+ ReadOnlyCollection<DnsQuestion> q = response.GetQuestions ();
+ if (q.Count != 1) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "QuestionCount 2";
+ return;
+ }
+ DnsQuestion question = q [0];
+ /* The answer might have dot at the end, etc...
+ if (String.Compare (question.Name, args.HostName) != 0) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "HostName - " + question.Name + " != " + args.HostName;
+ return;
+ }
+ */
+
+ DnsQType t = question.Type;
+ if (t != DnsQType.A && t != DnsQType.AAAA && t != DnsQType.PTR) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "QType " + question.Type;
+ return;
+ }
+
+ if (question.Class != DnsQClass.IN) {
+ args.ResolverError = ResolverError.ResponseHeaderError;
+ args.ErrorMessage = "QClass " + question.Class;
+ return;
+ }
+
+ ReadOnlyCollection<DnsResourceRecord> records = response.GetAnswers ();
+ if (records.Count == 0) {
+ if (args.PTRAddress != null) {
+ // PTR query failed -> no error
+ return;
+ }
+ args.ResolverError = ResolverError.NameError; // is this ok?
+ args.ErrorMessage = "NoAnswers";
+ return;
+ }
+
+ List<string> aliases = null;
+ List<IPAddress> addresses = null;
+ foreach (DnsResourceRecord r in records) {
+ if (r.Class != DnsClass.IN)
+ continue;
+ if (r.Type == DnsType.A || r.Type == DnsType.AAAA) {
+ if (addresses == null)
+ addresses = new List<IPAddress> ();
+ addresses.Add (((DnsResourceRecordIPAddress) r).Address);
+ } else if (r.Type == DnsType.CNAME) {
+ if (aliases == null)
+ aliases = new List<string> ();
+ aliases.Add (((DnsResourceRecordCName) r).CName);
+ } else if (r.Type == DnsType.PTR) {
+ args.HostEntry.HostName = ((DnsResourceRecordPTR) r).DName;
+ args.HostEntry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray ();
+ args.HostEntry.AddressList = EmptyAddresses;
+ return;
+ }
+ }
+
+ IPHostEntry entry = args.HostEntry ?? new IPHostEntry ();
+ if (entry.HostName == null && aliases != null && aliases.Count > 0) {
+ entry.HostName = aliases [0];
+ aliases.RemoveAt (0);
+ }
+ entry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray ();
+ entry.AddressList = addresses == null ? EmptyAddresses : addresses.ToArray ();
+ args.HostEntry = entry;
+ if ((question.Type == DnsQType.A || question.Type == DnsQType.AAAA) && entry.AddressList == EmptyAddresses) {
+ args.ResolverError = ResolverError.NameError;
+ args.ErrorMessage = "No addresses in response";
+ } else if (question.Type == DnsQType.PTR && entry.HostName == null) {
+ args.ResolverError = ResolverError.NameError;
+ args.ErrorMessage = "No PTR in response";
+ }
+
+ }
+
+ void InitFromSystem ()
+ {
+ List<IPEndPoint> eps = new List<IPEndPoint> ();
+ foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces ()) {
+ if (NetworkInterfaceType.Loopback == iface.NetworkInterfaceType)
+ continue;
+
+ foreach (IPAddress addr in iface.GetIPProperties ().DnsAddresses) {
+ if (AddressFamily.InterNetworkV6 == addr.AddressFamily)
+ continue;
+ IPEndPoint ep = new IPEndPoint (addr, 53);
+ if (eps.Contains (ep))
+ continue;
+
+ eps.Add (ep);
+ }
+ }
+ endpoints = eps.ToArray ();
+ }
+ }
+}
+
--- /dev/null
+//
+// Mono.Dns.SimpleResolverEventArgs
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//
+// Copyright 2011 Gonzalo Paniagua Javier
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+using System;
+using System.Net;
+using System.Threading;
+
+namespace Mono.Dns {
+#if !NET_2_0
+ public
+#endif
+ class SimpleResolverEventArgs : EventArgs {
+ public event EventHandler<SimpleResolverEventArgs> Completed;
+
+ public SimpleResolverEventArgs ()
+ {
+ }
+
+ public ResolverError ResolverError { get; set; }
+ public string ErrorMessage { get; set; }
+ public ResolverAsyncOperation LastOperation;
+ public string HostName { get; set; }
+ public IPHostEntry HostEntry { get; internal set; }
+ public object UserToken { get; set; }
+ internal ushort QueryID;
+ internal ushort Retries;
+ internal Timer Timer;
+ internal IPAddress PTRAddress;
+
+ internal void Reset (ResolverAsyncOperation op)
+ {
+ ResolverError = 0;
+ ErrorMessage = null;
+ HostEntry = null;
+ LastOperation = op;
+ QueryID = 0;
+ Retries = 0;
+ PTRAddress = null;
+ }
+
+ protected internal void OnCompleted (object sender)
+ {
+ var handler = Completed;
+ if (handler != null)
+ handler (sender, this);
+ }
+ }
+}
+
// Authors:
// Mads Pultz (mpultz@diku.dk)
// Lawrence Pit (loz@cable.a2000.nl)
-// Marek Safar (marek.safar@gmail.com)
+// Author: Mads Pultz (mpultz@diku.dk)
+// Lawrence Pit (loz@cable.a2000.nl)
+// Marek Safar (marek.safar@gmail.com)
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
//
// (C) Mads Pultz, 2001
-// Copyright 2011 Xamarin Inc.
+// Copyright (c) 2011 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
using System.Threading.Tasks;
#endif
+using Mono.Dns;
+
namespace System.Net {
public static class Dns {
+ static bool use_mono_dns;
+ static SimpleResolver resolver;
+
static Dns ()
{
System.Net.Sockets.Socket.CheckProtocolSupport();
+ if (Environment.GetEnvironmentVariable ("MONO_DNS") != null) {
+ resolver = new SimpleResolver ();
+ use_mono_dns = true;
+ }
+ }
+
+ internal static bool UseMonoDns {
+ get { return use_mono_dns; }
}
#if !MOONLIGHT // global remove of async methods
private delegate IPHostEntry GetHostEntryIPCallback (IPAddress hostAddress);
private delegate IPAddress [] GetHostAddressesCallback (string hostName);
+ static void OnCompleted (object sender, SimpleResolverEventArgs e)
+ {
+ DnsAsyncResult ares = (DnsAsyncResult) e.UserToken;
+ IPHostEntry entry = e.HostEntry;
+ if (entry == null || e.ResolverError != 0) {
+ ares.SetCompleted (false, new Exception ("Error: " + e.ResolverError));
+ return;
+ }
+ ares.SetCompleted (false, entry);
+ }
+
+ static IAsyncResult BeginAsyncCallAddresses (string host, AsyncCallback callback, object state)
+ {
+ SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
+ e.Completed += OnCompleted;
+ e.HostName = host;
+ DnsAsyncResult ares = new DnsAsyncResult (callback, state);
+ e.UserToken = ares;
+ if (resolver.GetHostAddressesAsync (e) == false)
+ ares.SetCompleted (true, e.HostEntry); // Completed synchronously
+ return ares;
+ }
+
+ static IAsyncResult BeginAsyncCall (string host, AsyncCallback callback, object state)
+ {
+ SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
+ e.Completed += OnCompleted;
+ e.HostName = host;
+ DnsAsyncResult ares = new DnsAsyncResult (callback, state);
+ e.UserToken = ares;
+ if (resolver.GetHostEntryAsync (e) == false)
+ ares.SetCompleted (true, e.HostEntry); // Completed synchronously
+ return ares;
+ }
+
+ static IPHostEntry EndAsyncCall (DnsAsyncResult ares)
+ {
+ if (ares == null)
+ throw new ArgumentException ("Invalid asyncResult");
+ if (!ares.IsCompleted)
+ ares.AsyncWaitHandle.WaitOne ();
+ if (ares.Exception != null)
+ throw ares.Exception;
+ IPHostEntry entry = ares.HostEntry;
+ if (entry == null || entry.AddressList == null || entry.AddressList.Length == 0)
+ throw new SocketException(11001);
+ return entry;
+ }
+
[Obsolete ("Use BeginGetHostEntry instead")]
- public static IAsyncResult BeginGetHostByName (string hostName,
- AsyncCallback requestCallback, object stateObject)
+ public static IAsyncResult BeginGetHostByName (string hostName, AsyncCallback requestCallback, object stateObject)
{
if (hostName == null)
throw new ArgumentNullException ("hostName");
+ if (use_mono_dns)
+ return BeginAsyncCall (hostName, requestCallback, stateObject);
+
GetHostByNameCallback c = new GetHostByNameCallback (GetHostByName);
return c.BeginInvoke (hostName, requestCallback, stateObject);
}
[Obsolete ("Use BeginGetHostEntry instead")]
- public static IAsyncResult BeginResolve (string hostName,
- AsyncCallback requestCallback, object stateObject)
+ public static IAsyncResult BeginResolve (string hostName, AsyncCallback requestCallback, object stateObject)
{
if (hostName == null)
throw new ArgumentNullException ("hostName");
+ if (use_mono_dns)
+ return BeginAsyncCall (hostName, requestCallback, stateObject);
+
ResolveCallback c = new ResolveCallback (Resolve);
return c.BeginInvoke (hostName, requestCallback, stateObject);
}
- public static IAsyncResult BeginGetHostAddresses (string hostNameOrAddress,
- AsyncCallback requestCallback, object state)
+ public static IAsyncResult BeginGetHostAddresses (string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
{
if (hostNameOrAddress == null)
throw new ArgumentNullException ("hostName");
"cannot use them as target address.",
"hostNameOrAddress");
+ if (use_mono_dns)
+ return BeginAsyncCallAddresses (hostNameOrAddress, requestCallback, stateObject);
+
GetHostAddressesCallback c = new GetHostAddressesCallback (GetHostAddresses);
return c.BeginInvoke (hostNameOrAddress, requestCallback, state);
}
- public static IAsyncResult BeginGetHostEntry (string hostNameOrAddress,
- AsyncCallback requestCallback, object stateObject)
+ public static IAsyncResult BeginGetHostEntry (string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
{
if (hostNameOrAddress == null)
throw new ArgumentNullException ("hostName");
"cannot use them as target address.",
"hostNameOrAddress");
+ if (use_mono_dns)
+ return BeginAsyncCall (hostNameOrAddress, requestCallback, stateObject);
+
GetHostEntryNameCallback c = new GetHostEntryNameCallback (GetHostEntry);
return c.BeginInvoke (hostNameOrAddress, requestCallback, stateObject);
}
- public static IAsyncResult BeginGetHostEntry (IPAddress address,
- AsyncCallback requestCallback, object stateObject)
+ public static IAsyncResult BeginGetHostEntry (IPAddress address, AsyncCallback requestCallback, object stateObject)
{
if (address == null)
throw new ArgumentNullException ("address");
+ if (use_mono_dns)
+ return BeginAsyncCall (address.ToString (), requestCallback, stateObject);
+
GetHostEntryIPCallback c = new GetHostEntryIPCallback (GetHostEntry);
return c.BeginInvoke (address, requestCallback, stateObject);
}
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
+ if (use_mono_dns)
+ return EndAsyncCall (asyncResult as DnsAsyncResult);
+
AsyncResult async = (AsyncResult) asyncResult;
GetHostByNameCallback cb = (GetHostByNameCallback) async.AsyncDelegate;
return cb.EndInvoke(asyncResult);
{
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
+
+ if (use_mono_dns)
+ return EndAsyncCall (asyncResult as DnsAsyncResult);
+
AsyncResult async = (AsyncResult) asyncResult;
ResolveCallback cb = (ResolveCallback) async.AsyncDelegate;
return cb.EndInvoke(asyncResult);
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
+ if (use_mono_dns) {
+ IPHostEntry entry = EndAsyncCall (asyncResult as DnsAsyncResult);
+ if (entry == null)
+ return null;
+ return entry.AddressList;
+ }
+
AsyncResult async = (AsyncResult) asyncResult;
GetHostAddressesCallback cb = (GetHostAddressesCallback) async.AsyncDelegate;
return cb.EndInvoke(asyncResult);
{
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
+
+ if (use_mono_dns)
+ return EndAsyncCall (asyncResult as DnsAsyncResult);
+
AsyncResult async = (AsyncResult) asyncResult;
if (async.AsyncDelegate is GetHostEntryIPCallback)
return ((GetHostEntryIPCallback) async.AsyncDelegate).EndInvoke (asyncResult);
--- /dev/null
+//
+// System.Net.DnsAsyncResult
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+using System.Threading;
+using Mono.Dns;
+
+namespace System.Net
+{
+ class DnsAsyncResult : IAsyncResult
+ {
+ static WaitCallback internal_cb = new WaitCallback (CB);
+ ManualResetEvent handle;
+ bool synch;
+ bool is_completed;
+ AsyncCallback callback;
+ object state;
+ IPHostEntry entry;
+ Exception exc;
+
+ public DnsAsyncResult (AsyncCallback cb, object state)
+ {
+ this.callback = cb;
+ this.state = state;
+ }
+
+ public void SetCompleted (bool synch, IPHostEntry entry, Exception e)
+ {
+ this.synch = synch;
+ this.entry = entry;
+ exc = e;
+ lock (this) {
+ if (is_completed)
+ return;
+ is_completed = true;
+ if (handle != null)
+ handle.Set ();
+ }
+ if (callback != null)
+ ThreadPool.QueueUserWorkItem (internal_cb, this);
+ }
+
+ public void SetCompleted (bool synch, Exception e)
+ {
+ SetCompleted (synch, null, e);
+ }
+
+ public void SetCompleted (bool synch, IPHostEntry entry)
+ {
+ SetCompleted (synch, entry, null);
+ }
+
+ static void CB (object _this)
+ {
+ DnsAsyncResult ares = (DnsAsyncResult) _this;
+ ares.callback (ares);
+ }
+
+ public object AsyncState {
+ get { return state; }
+ }
+
+ public WaitHandle AsyncWaitHandle {
+ get {
+ lock (this) {
+ if (handle == null)
+ handle = new ManualResetEvent (is_completed);
+ }
+ return handle;
+ }
+ }
+
+ public Exception Exception {
+ get { return exc; }
+ }
+
+ public IPHostEntry HostEntry {
+ get { return entry; }
+ }
+
+ public bool CompletedSynchronously {
+ get { return synch; }
+ }
+
+ public bool IsCompleted {
+ get {
+ lock (this) {
+ return is_completed;
+ }
+ }
+ }
+ }
+}
+
../corlib/System.Collections/CollectionDebuggerView.cs
../corlib/System.Collections.Generic/CollectionDebuggerView.cs
../corlib/Mono/DataConverter.cs
+Mono.Dns/DnsClass.cs
+Mono.Dns/DnsHeader.cs
+Mono.Dns/DnsOpCode.cs
+Mono.Dns/DnsPacket.cs
+Mono.Dns/DnsQClass.cs
+Mono.Dns/DnsQType.cs
+Mono.Dns/DnsQuery.cs
+Mono.Dns/DnsQuestion.cs
+Mono.Dns/DnsRCode.cs
+Mono.Dns/DnsResourceRecordA.cs
+Mono.Dns/DnsResourceRecordAAAA.cs
+Mono.Dns/DnsResourceRecordCName.cs
+Mono.Dns/DnsResourceRecord.cs
+Mono.Dns/DnsResourceRecordIPAddress.cs
+Mono.Dns/DnsResourceRecordPTR.cs
+Mono.Dns/DnsResponse.cs
+Mono.Dns/DnsType.cs
+Mono.Dns/DnsUtil.cs
+Mono.Dns/ResolverAsyncOperation.cs
+Mono.Dns/SimpleResolver.cs
+Mono.Dns/ResolverError.cs
+Mono.Dns/SimpleResolverEventArgs.cs
+System.Net/DnsAsyncResult.cs