• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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