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 = 0; // NS_R_NO_ERROR 72 int linux_errno = 0; // SYS_NO_ERROR 73 std::chrono::microseconds latencyUs; 74 }; 75 76 StatsRecords(const netdutils::IPSockAddr& ipSockAddr, size_t size); 77 78 void push(const Record& record); 79 getStatsData()80 const StatsData& getStatsData() const { return mStatsData; } 81 82 // Quantifies the quality based on the current quality factors and the latency, and normalize 83 // the value to a score between 0 to 100. 84 double score() const; 85 86 void incrementSkippedCount(); 87 88 private: 89 void updateStatsData(const Record& record, const bool add); 90 void updatePenalty(const Record& record); 91 92 std::deque<Record> mRecords; 93 size_t mCapacity; 94 StatsData mStatsData; 95 96 // A quality factor used to distinguish if the server can't be evaluated by latency alone, such 97 // as instant failure on connect. 98 int mPenalty = 0; 99 100 // A quality factor used to prevent starvation. 101 int mSkippedCount = 0; 102 103 // The maximum of the quantified result. As the sorting is on the basis of server latency, limit 104 // the maximal value of the quantity to 10000 in correspondence with the maximal cleartext 105 // query timeout 10000 milliseconds. This helps normalize the value of the quality to a score. 106 static constexpr int kMaxQuality = 10000; 107 }; 108 109 // DnsStats class manages the statistics of DNS servers per netId. 110 // The class itself is not thread-safe. 111 class DnsStats { 112 public: 113 using ServerStatsMap = std::map<netdutils::IPSockAddr, StatsRecords>; 114 115 // Add |servers| to the map, and remove no-longer-used servers. 116 // Return true if they are successfully added; otherwise, return false. 117 bool setServers(const std::vector<netdutils::IPSockAddr>& servers, Protocol protocol); 118 119 // Return true if |record| is successfully added into |server|'s stats; otherwise, return false. 120 bool addStats(const netdutils::IPSockAddr& server, const DnsQueryEvent& record); 121 122 std::vector<netdutils::IPSockAddr> getSortedServers(Protocol protocol) const; 123 124 // Returns the average query latency in microseconds. 125 std::optional<std::chrono::microseconds> getAverageLatencyUs(Protocol protocol) const; 126 127 void dump(netdutils::DumpWriter& dw); 128 129 std::vector<StatsData> getStats(Protocol protocol) const; 130 131 // TODO: Compatible support for getResolverInfo(). 132 133 static constexpr size_t kLogSize = 128; 134 135 private: 136 std::map<Protocol, ServerStatsMap> mStats; 137 }; 138 139 } // namespace android::net 140