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/format.h>
22 
23 namespace android::net::metrics {
24 
25 using android::base::ScopedLockAssertion;
26 using std::chrono::milliseconds;
27 
28 constexpr milliseconds kEventTimeoutMs{5000};
29 
operator ==(const DnsMetricsListener::DnsEvent & o) const30 bool DnsMetricsListener::DnsEvent::operator==(const DnsMetricsListener::DnsEvent& o) const {
31     return std::tie(netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount) ==
32            std::tie(o.netId, o.eventType, o.returnCode, o.hostname, o.ipAddresses,
33                     o.ipAddressesCount);
34 }
35 
operator <<(std::ostream & os,const DnsMetricsListener::DnsEvent & data)36 std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& data) {
37     return os << fmt::format("[{}, {}, {}, {}, [{}], {}]", data.netId, data.eventType,
38                              data.returnCode, data.hostname, fmt::join(data.ipAddresses, ", "),
39                              data.ipAddressesCount);
40 }
41 
onNat64PrefixEvent(int32_t netId,bool added,const std::string & prefixString,int32_t)42 ::ndk::ScopedAStatus DnsMetricsListener::onNat64PrefixEvent(int32_t netId, bool added,
43                                                             const std::string& prefixString,
44                                                             int32_t /*prefixLength*/) {
45     std::lock_guard lock(mMutex);
46     mUnexpectedNat64PrefixUpdates++;
47     if (netId == mNetId) mNat64Prefix = added ? prefixString : "";
48     mCv.notify_all();
49     return ::ndk::ScopedAStatus::ok();
50 }
51 
onPrivateDnsValidationEvent(int32_t netId,const std::string & ipAddress,const std::string &,bool validated)52 ::ndk::ScopedAStatus DnsMetricsListener::onPrivateDnsValidationEvent(
53         int32_t netId, const std::string& ipAddress, const std::string& /*hostname*/,
54         bool validated) {
55     {
56         std::lock_guard lock(mMutex);
57         // keep updating the server to have latest validation status.
58         mValidationRecords.insert_or_assign({netId, ipAddress}, validated);
59     }
60     mCv.notify_all();
61     return ::ndk::ScopedAStatus::ok();
62 }
63 
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)64 ::ndk::ScopedAStatus DnsMetricsListener::onDnsEvent(int32_t netId, int32_t eventType,
65                                                     int32_t returnCode, int32_t /*latencyMs*/,
66                                                     const std::string& hostname,
67                                                     const std::vector<std::string>& ipAddresses,
68                                                     int32_t ipAddressesCount, int32_t /*uid*/) {
69     std::lock_guard lock(mMutex);
70     if (netId == mNetId) {
71         mDnsEventRecords.push(
72                 {netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount});
73     }
74     mCv.notify_all();
75     return ::ndk::ScopedAStatus::ok();
76 }
77 
waitForNat64Prefix(ExpectNat64PrefixStatus status,milliseconds timeout)78 bool DnsMetricsListener::waitForNat64Prefix(ExpectNat64PrefixStatus status, milliseconds timeout) {
79     std::unique_lock lock(mMutex);
80     ScopedLockAssertion assume_lock(mMutex);
81 
82     if (mCv.wait_for(lock, timeout, [&]() REQUIRES(mMutex) {
83             return (status == EXPECT_FOUND && !mNat64Prefix.empty()) ||
84                    (status == EXPECT_NOT_FOUND && mNat64Prefix.empty());
85         })) {
86         mUnexpectedNat64PrefixUpdates--;
87         return true;
88     }
89 
90     // Timeout.
91     return false;
92 }
93 
waitForPrivateDnsValidation(const std::string & serverAddr,const bool validated)94 bool DnsMetricsListener::waitForPrivateDnsValidation(const std::string& serverAddr,
95                                                      const bool validated) {
96     std::unique_lock lock(mMutex);
97     return mCv.wait_for(lock, kEventTimeoutMs, [&]() REQUIRES(mMutex) {
98         return findAndRemoveValidationRecord({mNetId, serverAddr}, validated);
99     });
100 }
101 
findAndRemoveValidationRecord(const ServerKey & key,const bool value)102 bool DnsMetricsListener::findAndRemoveValidationRecord(const ServerKey& key, const bool value) {
103     auto it = mValidationRecords.find(key);
104     if (it != mValidationRecords.end() && it->second == value) {
105         mValidationRecords.erase(it);
106         return true;
107     }
108     return false;
109 }
110 
popDnsEvent()111 std::optional<DnsMetricsListener::DnsEvent> DnsMetricsListener::popDnsEvent() {
112     std::unique_lock lock(mMutex);
113     ScopedLockAssertion assume_lock(mMutex);
114 
115     if (!mCv.wait_for(lock, kEventTimeoutMs,
116                       [&]() REQUIRES(mMutex) { return !mDnsEventRecords.empty(); })) {
117         return std::nullopt;
118     }
119 
120     auto ret = mDnsEventRecords.front();
121     mDnsEventRecords.pop();
122     return ret;
123 }
124 
125 }  // namespace android::net::metrics
126