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