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 #pragma once
18 
19 #include <condition_variable>
20 #include <map>
21 #include <queue>
22 #include <utility>
23 
24 #include <android-base/thread_annotations.h>
25 
26 #include "base_metrics_listener.h"
27 
28 enum ExpectNat64PrefixStatus : bool {
29     EXPECT_FOUND,
30     EXPECT_NOT_FOUND,
31 };
32 
33 namespace android {
34 namespace net {
35 namespace metrics {
36 
37 // TODO: Perhaps use condition variable but continually polling.
38 // TODO: Perhaps create a queue to monitor the event changes. That improves the unit test which can
39 // verify the event count, the event change order, and so on.
40 class DnsMetricsListener : public BaseMetricsListener {
41   public:
42     struct DnsEvent {
43         int32_t netId;
44         int32_t eventType;
45         int32_t returnCode;
46         std::string hostname;
47         std::vector<std::string> ipAddresses;
48         int32_t ipAddressesCount;
49 
50         bool operator==(const DnsEvent& o) const;
51 
52         // Informative for debugging.
53         friend std::ostream& operator<<(std::ostream& os, const DnsEvent& data);
54     };
55 
56     DnsMetricsListener() = delete;
DnsMetricsListener(int32_t netId)57     DnsMetricsListener(int32_t netId) : mNetId(netId){};
58 
59     // Override DNS metrics event(s).
60     ::ndk::ScopedAStatus onNat64PrefixEvent(int32_t netId, bool added,
61                                             const std::string& prefixString,
62                                             int32_t /*prefixLength*/) override;
63 
64     ::ndk::ScopedAStatus onPrivateDnsValidationEvent(int32_t netId, const std::string& ipAddress,
65                                                      const std::string& /*hostname*/,
66                                                      bool validated) override;
67 
68     ::ndk::ScopedAStatus onDnsEvent(int32_t netId, int32_t eventType, int32_t returnCode,
69                                     int32_t /*latencyMs*/, const std::string& hostname,
70                                     const std::vector<std::string>& ipAddresses,
71                                     int32_t ipAddressesCount, int32_t /*uid*/) override;
72 
73     // Wait for expected NAT64 prefix status until timeout.
74     bool waitForNat64Prefix(ExpectNat64PrefixStatus status, std::chrono::milliseconds timeout)
75             EXCLUDES(mMutex);
76 
77     // Returns the number of updates to the NAT64 prefix that have not yet been waited for.
getUnexpectedNat64PrefixUpdates()78     int getUnexpectedNat64PrefixUpdates() const EXCLUDES(mMutex) {
79         std::lock_guard lock(mMutex);
80         return mUnexpectedNat64PrefixUpdates;
81     }
82 
83     // Wait for the expected private DNS validation result until timeout.
84     bool waitForPrivateDnsValidation(const std::string& serverAddr, const bool validated);
85 
86     // Return true if a validation result for |serverAddr| is found; otherwise, return false.
87     // Only exists for testing.
findValidationRecord(const std::string & serverAddr)88     bool findValidationRecord(const std::string& serverAddr) const EXCLUDES(mMutex) {
89         std::lock_guard lock(mMutex);
90         return mValidationRecords.find({mNetId, serverAddr}) != mValidationRecords.end();
91     }
92 
93     std::optional<DnsEvent> popDnsEvent() EXCLUDES(mMutex);
94 
reset()95     void reset() EXCLUDES(mMutex) {
96         std::lock_guard lock(mMutex);
97         mUnexpectedNat64PrefixUpdates = 0;
98         mValidationRecords.clear();
99 
100         std::queue<DnsEvent> emptyQueue;
101         std::swap(mDnsEventRecords, emptyQueue);
102     }
103 
104   private:
105     typedef std::pair<int32_t, std::string> ServerKey;
106 
107     // Search mValidationRecords. Return true if |key| exists and its value is equal to
108     // |value|, and then remove it; otherwise, return false.
109     bool findAndRemoveValidationRecord(const ServerKey& key, const bool value) REQUIRES(mMutex);
110 
111     // Monitor the event which was fired on specific network id.
112     const int32_t mNetId;
113 
114     // The NAT64 prefix of the network |mNetId|. It is updated by the event onNat64PrefixEvent().
115     std::string mNat64Prefix GUARDED_BY(mMutex);
116 
117     // The number of updates to the NAT64 prefix of network |mNetId| that have not yet been waited
118     // for. Increases by 1 every time onNat64PrefixEvent is called, and decreases by 1 every time
119     // waitForNat64Prefix returns true.
120     // This allows tests to check that no unexpected events have been received without having to
121     // resort to timeouts that make the tests slower and flakier.
122     int mUnexpectedNat64PrefixUpdates GUARDED_BY(mMutex);
123 
124     // Used to store the data from onPrivateDnsValidationEvent.
125     std::map<ServerKey, bool> mValidationRecords GUARDED_BY(mMutex);
126 
127     // Used to store the data from onDnsEvent.
128     std::queue<DnsEvent> mDnsEventRecords GUARDED_BY(mMutex);
129 
130     mutable std::mutex mMutex;
131     std::condition_variable mCv;
132 };
133 
134 }  // namespace metrics
135 }  // namespace net
136 }  // namespace android
137