1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 #pragma once 19 20 #include <chrono> 21 #include <deque> 22 #include <map> 23 #include <vector> 24 25 #include <android-base/thread_annotations.h> 26 #include <netdutils/DumpWriter.h> 27 #include <netdutils/InternetAddresses.h> 28 29 #include "ResolverStats.h" 30 #include "stats.pb.h" 31 32 namespace android::net { 33 34 // The overall information of a StatsRecords. 35 struct StatsData { StatsDataStatsData36 StatsData(const netdutils::IPSockAddr& ipSockAddr) : serverSockAddr(ipSockAddr) { 37 lastUpdate = std::chrono::steady_clock::now(); 38 }; 39 40 // Server socket address. 41 netdutils::IPSockAddr serverSockAddr; 42 43 // The most recent number of records being accumulated. 44 int total = 0; 45 46 // The map used to store the number of each rcode. 47 std::map<int, int> rcodeCounts; 48 49 // The aggregated RTT in microseconds. 50 // For DNS-over-TCP, it includes TCP handshake. 51 // For DNS-over-TLS, it might include TCP handshake plus SSL handshake. 52 std::chrono::microseconds latencyUs = {}; 53 54 // The last update timestamp. 55 std::chrono::time_point<std::chrono::steady_clock> lastUpdate; 56 57 int averageLatencyMs() const; 58 std::string toString() const; 59 60 // For testing. 61 bool operator==(const StatsData& o) const; 62 friend std::ostream& operator<<(std::ostream& os, const StatsData& data) { 63 return os << data.toString(); 64 } 65 }; 66 67 // A circular buffer based class used to store the statistics for a server with a protocol. 68 class StatsRecords { 69 public: 70 struct Record { 71 int rcode; 72 std::chrono::microseconds latencyUs; 73 }; 74 75 StatsRecords(const netdutils::IPSockAddr& ipSockAddr, size_t size); 76 77 void push(const Record& record); 78 getStatsData()79 const StatsData& getStatsData() const { return mStatsData; } 80 81 // Quantifies the quality based on the current quality factors and the latency, and normalize 82 // the value to a score between 0 to 100. 83 double score() const; 84 85 void incrementSkippedCount(); 86 87 private: 88 void updateStatsData(const Record& record, const bool add); 89 void updatePenalty(const Record& record); 90 91 std::deque<Record> mRecords; 92 size_t mCapacity; 93 StatsData mStatsData; 94 95 // A quality factor used to distinguish if the server can't be evaluated by latency alone, such 96 // as instant failure on connect. 97 int mPenalty = 0; 98 99 // A quality factor used to prevent starvation. 100 int mSkippedCount = 0; 101 102 // The maximum of the quantified result. As the sorting is on the basis of server latency, limit 103 // the maximal value of the quantity to 10000 in correspondence with the maximal cleartext 104 // query timeout 10000 milliseconds. This helps normalize the value of the quality to a score. 105 static constexpr int kMaxQuality = 10000; 106 }; 107 108 // DnsStats class manages the statistics of DNS servers per netId. 109 // The class itself is not thread-safe. 110 class DnsStats { 111 public: 112 using ServerStatsMap = std::map<netdutils::IPSockAddr, StatsRecords>; 113 114 // Add |servers| to the map, and remove no-longer-used servers. 115 // Return true if they are successfully added; otherwise, return false. 116 bool setServers(const std::vector<netdutils::IPSockAddr>& servers, Protocol protocol); 117 118 // Return true if |record| is successfully added into |server|'s stats; otherwise, return false. 119 bool addStats(const netdutils::IPSockAddr& server, const DnsQueryEvent& record); 120 121 std::vector<netdutils::IPSockAddr> getSortedServers(Protocol protocol) const; 122 123 void dump(netdutils::DumpWriter& dw); 124 125 // For testing. 126 std::vector<StatsData> getStats(Protocol protocol) const; 127 128 // TODO: Compatible support for getResolverInfo(). 129 130 static constexpr size_t kLogSize = 128; 131 132 private: 133 std::map<Protocol, ServerStatsMap> mStats; 134 }; 135 136 } // namespace android::net 137