// Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // // This program is also distributed with certain software (including // but not limited to OpenSSL) that is licensed under separate terms, // as designated in a particular file or component or in included license // documentation. The authors of MySQL hereby grant you an // additional permission to link the program and your derivative works // with the separately licensed software that they have included with // MySQL. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the // Universal FOSS Exception, version 1.0, a copy of which can be found at // http://oss.oracle.com/licenses/universal-foss-exception. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License, version 2.0, for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using Ubiety.Dns.Core; using System; using System.Collections.Generic; using System.Linq; using Ubiety.Dns.Core.Common; using MySql.Data.MySqlClient; using Sog.Properties; namespace MySql.Data.Common { /// /// DNS resolver that runs queries against a server. /// internal static class DnsResolver { // Resolver object that looks up for DNS SRV records. private static Resolver _resolver; // DNS domain. internal static string ServiceName { get; private set; } /// /// Initializes a new instance of the class. /// internal static void CreateResolver(string serviceName) { _resolver = new Resolver { Recursion = true, UseCache = true, Retries = 3, TransportType = TransportType.Udp }; ServiceName = serviceName; } /// /// Gets the DNS SVR records of the service name that is provided. /// /// A list of s sorted as described in RFC2782. internal static List GetDnsSrvRecords(string serviceName) { if (_resolver == null) { CreateResolver(serviceName); } List records = new List(); const QuestionType qType = QuestionType.SRV; const QuestionClass qClass = QuestionClass.IN; Response response = _resolver.Query(ServiceName, qType, qClass); #pragma warning disable CS0618 // “Response.RecordSrv”已过时:“Use GetRecords instead.” foreach (var record in response.RecordSrv) #pragma warning restore CS0618 // “Response.RecordSrv”已过时:“Use GetRecords instead.” { records.Add(record); } if (records.Count > 0) { Reset(); return SortSrvRecords(records); } else { throw new MySqlException(string.Format(Resources.DnsSrvNoHostsAvailable, ServiceName)); } } /// /// Sorts a list of DNS SRV records according to the sorting rules described in RFC2782. /// /// List of s to sort. /// A new list of sorted s. internal static List SortSrvRecords(List srvRecords) { srvRecords.Sort(new DnsSrvRecord()); Random random = new Random(); List srvRecordsSortedRfc2782 = new List(); List priorities = srvRecords.Select(s => s.Priority).Distinct().ToList(); foreach (int priority in priorities) { List srvRecordsSamePriority = srvRecords.Where(r => r.Priority == priority).ToList(); while (srvRecordsSamePriority.Count > 1) { int recCount = srvRecordsSamePriority.Count; int sumOfWeights = 0; int[] weights = new int[recCount]; for (int i = 0; i < recCount; i++) { sumOfWeights += srvRecordsSamePriority[i].Weight; weights[i] = sumOfWeights; } int selection = random.Next(sumOfWeights + 1); int pos = 0; for (; pos < recCount && weights[pos] < selection; pos++) { } srvRecordsSortedRfc2782.Add(srvRecordsSamePriority[pos]); srvRecordsSamePriority.RemoveAt(pos); } srvRecordsSortedRfc2782.Add(srvRecordsSamePriority[0]); } return srvRecordsSortedRfc2782; } /// /// Resets the DnsSrvResolver /// private static void Reset() { if (_resolver != null) { _resolver = null; } } } }