private static SRVRecord PickSRV(SRVRecord[] srv) { // TODO: keep track of connection failures, and try the next priority down. if ((srv == null) || (srv.Length == 0)) throw new ArgumentException(); if (srv.Length == 1) return srv[0]; // randomize order. One might wish that the OS would have done this for us. // cf. Bob Schriter's Grandfather. Random rnd = new Random(); byte[] keys = new byte[srv.Length]; rnd.NextBytes(keys); Array.Sort(keys, srv); // Permute me, Knuth! (I wish I had a good anagram for that) int minpri = int.MaxValue; foreach (SRVRecord rec in srv) { if (rec.Priority < minpri) minpri = rec.Priority; } int weight = 0; foreach (SRVRecord rec in srv) { if (rec.Priority == minpri) weight += rec.Weight; } int pos = rnd.Next(weight); weight = 0; foreach (SRVRecord rec in srv) { if (rec.Priority == minpri) { weight += rec.Weight; if ((pos < weight) || (weight == 0)) return rec; } } throw new DnsException("No matching SRV"); }
public static SRVRecord[] ResolveSRV(string query) { byte[] buffer = new byte[1024]; byte[] name = new byte[256]; ushort type, dlen, priority, weight, port; int size; GCHandle handle; List<SRVRecord> results = new List<SRVRecord>(); size = res_query(query, C_IN, T_SRV, buffer, buffer.Length); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { HEADER header = (HEADER)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HEADER)); int qdcount = ntohs(header.qdcount); int ancount = ntohs(header.ancount); int headerSize = Marshal.SizeOf(header); unsafe { fixed (byte* pBuffer = buffer) { byte* pos = pBuffer + headerSize; byte* end = pBuffer + size; // We don't care about the question section. while (qdcount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; pos += size + 4; } // The answers, however, we do care about! while (ancount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; pos += size; type = GETSHORT(ref pos); // Skip TTL pos += 6; dlen = GETSHORT(ref pos); if (type == T_SRV) { priority = GETSHORT(ref pos); weight = GETSHORT(ref pos); port = GETSHORT(ref pos); size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; string nameStr = null; fixed (byte* pName = name) { nameStr = new String((sbyte*)pName); } var record = new SRVRecord(); record.NameNext = nameStr; record.Priority = priority; record.Weight = weight; record.Port = port; results.Add(record); pos += size; } else { pos += dlen; } } } } } finally { handle.Free(); } return results.ToArray(); }