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 #include "dns_metrics_listener.h"
18 
19 #include <thread>
20 
21 #include <android-base/chrono_utils.h>
22 #include <android-base/format.h>
23 
24 namespace android {
25 namespace net {
26 namespace metrics {
27 
28 using android::base::ScopedLockAssertion;
29 using std::chrono::milliseconds;
30 
31 constexpr milliseconds kRetryIntervalMs{20};
32 constexpr milliseconds kEventTimeoutMs{5000};
33 
operator ==(const DnsMetricsListener::DnsEvent & o) const34 bool DnsMetricsListener::DnsEvent::operator==(const DnsMetricsListener::DnsEvent& o) const {
35     return std::tie(netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount) ==
36            std::tie(o.netId, o.eventType, o.returnCode, o.hostname, o.ipAddresses,
37                     o.ipAddressesCount);
38 }
39 
operator <<(std::ostream & os,const DnsMetricsListener::DnsEvent & data)40 std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& data) {
41     return os << fmt::format("[{}, {}, {}, {}, [{}], {}]", data.netId, data.eventType,
42                              data.returnCode, data.hostname, fmt::join(data.ipAddresses, ", "),
43                              data.ipAddressesCount);
44 }
45 
onNat64PrefixEvent(int32_t netId,bool added,const std::string & prefixString,int32_t)46 ::ndk::ScopedAStatus DnsMetricsListener::onNat64PrefixEvent(int32_t netId, bool added,
47                                                             const std::string& prefixString,
48                                                             int32_t /*prefixLength*/) {
49     std::lock_guard lock(mMutex);
50     mUnexpectedNat64PrefixUpdates++;
51     if (netId == mNetId) mNat64Prefix = added ? prefixString : "";
52     return ::ndk::ScopedAStatus::ok();
53 }
54 
onPrivateDnsValidationEvent(int32_t netId,const std::string & ipAddress,const std::string &,bool validated)55 ::ndk::ScopedAStatus DnsMetricsListener::onPrivateDnsValidationEvent(
56         int32_t netId, const std::string& ipAddress, const std::string& /*hostname*/,
57         bool validated) {
58     {
59         std::lock_guard lock(mMutex);
60         // keep updating the server to have latest validation status.
61         mValidationRecords.insert_or_assign({netId, ipAddress}, validated);
62     }
63     mCv.notify_one();
64     return ::ndk::ScopedAStatus::ok();
65 }
66 
onDnsEvent(int32_t netId,int32_t eventType,int32_t returnCode,int32_t,const std::string & hostname,const std::vector<std::string> & ipAddresses,int32_t ipAddressesCount,int32_t)67 ::ndk::ScopedAStatus DnsMetricsListener::onDnsEvent(int32_t netId, int32_t eventType,
68                                                     int32_t returnCode, int32_t /*latencyMs*/,
69                                                     const std::string& hostname,
70                                                     const std::vector<std::string>& ipAddresses,
71                                                     int32_t ipAddressesCount, int32_t /*uid*/) {
72     std::lock_guard lock(mMutex);
73     if (netId == mNetId) {
74         mDnsEventRecords.push(
75                 {netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount});
76     }
77     return ::ndk::ScopedAStatus::ok();
78 }
79 
waitForNat64Prefix(ExpectNat64PrefixStatus status,milliseconds timeout)80 bool DnsMetricsListener::waitForNat64Prefix(ExpectNat64PrefixStatus status, milliseconds timeout) {
81     android::base::Timer t;
82     while (t.duration() < timeout) {
83         {
84             std::lock_guard lock(mMutex);
85             if ((status == EXPECT_FOUND && !mNat64Prefix.empty()) ||
86                 (status == EXPECT_NOT_FOUND && mNat64Prefix.empty())) {
87                 mUnexpectedNat64PrefixUpdates--;
88                 return true;
89             }
90         }
91         std::this_thread::sleep_for(kRetryIntervalMs);
92     }
93     return false;
94 }
95 
waitForPrivateDnsValidation(const std::string & serverAddr,const bool validated)96 bool DnsMetricsListener::waitForPrivateDnsValidation(const std::string& serverAddr,
97                                                      const bool validated) {
98     const auto now = std::chrono::steady_clock::now();
99 
100     std::unique_lock lock(mMutex);
101     ScopedLockAssertion assume_lock(mMutex);
102 
103     // onPrivateDnsValidationEvent() might already be invoked. Search for the record first.
104     do {
105         if (findAndRemoveValidationRecord({mNetId, serverAddr}, validated)) return true;
106     } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);
107 
108     // Timeout.
109     return false;
110 }
111 
findAndRemoveValidationRecord(const ServerKey & key,const bool value)112 bool DnsMetricsListener::findAndRemoveValidationRecord(const ServerKey& key, const bool value) {
113     auto it = mValidationRecords.find(key);
114     if (it != mValidationRecords.end() && it->second == value) {
115         mValidationRecords.erase(it);
116         return true;
117     }
118     return false;
119 }
120 
popDnsEvent()121 std::optional<DnsMetricsListener::DnsEvent> DnsMetricsListener::popDnsEvent() {
122     // Wait until the queue is not empty or timeout.
123     android::base::Timer t;
124     while (t.duration() < milliseconds{1000}) {
125         {
126             std::lock_guard lock(mMutex);
127             if (!mDnsEventRecords.empty()) break;
128         }
129         std::this_thread::sleep_for(kRetryIntervalMs);
130     }
131 
132     std::lock_guard lock(mMutex);
133     if (mDnsEventRecords.empty()) return std::nullopt;
134 
135     auto ret = mDnsEventRecords.front();
136     mDnsEventRecords.pop();
137     return ret;
138 }
139 
140 }  // namespace metrics
141 }  // namespace net
142 }  // namespace android
143