1 /**
2 * Copyright (c) 2021, 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 "unsolicited_event_listener.h"
18
19 #include <thread>
20
21 #include <android-base/chrono_utils.h>
22 #include <android-base/format.h>
23
24 namespace android::net::resolv::aidl {
25
26 using ::aidl::android::net::resolv::aidl::DnsHealthEventParcel;
27 using ::aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
28 using ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
29 using ::aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
30 using android::base::Error;
31 using android::base::Result;
32 using android::base::ScopedLockAssertion;
33 using std::chrono::milliseconds;
34
35 constexpr milliseconds kEventTimeoutMs{5000};
36 constexpr milliseconds kRetryIntervalMs{20};
37
onDnsHealthEvent(const DnsHealthEventParcel & event)38 ::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(const DnsHealthEventParcel& event) {
39 std::lock_guard lock(mMutex);
40 if (event.netId == mNetId) mDnsHealthResultRecords.push(event.healthResult);
41 return ::ndk::ScopedAStatus::ok();
42 }
43
onNat64PrefixEvent(const Nat64PrefixEventParcel & event)44 ::ndk::ScopedAStatus UnsolicitedEventListener::onNat64PrefixEvent(
45 const Nat64PrefixEventParcel& event) {
46 std::lock_guard lock(mMutex);
47 mUnexpectedNat64PrefixUpdates++;
48 if (event.netId == mNetId) {
49 mNat64PrefixAddress = (event.prefixOperation ==
50 IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED)
51 ? event.prefixAddress
52 : "";
53 }
54 return ::ndk::ScopedAStatus::ok();
55 }
56
onPrivateDnsValidationEvent(const PrivateDnsValidationEventParcel & event)57 ::ndk::ScopedAStatus UnsolicitedEventListener::onPrivateDnsValidationEvent(
58 const PrivateDnsValidationEventParcel& event) {
59 {
60 std::lock_guard lock(mMutex);
61 // keep updating the server to have latest validation status.
62 mValidationRecords.insert_or_assign({event.netId, event.ipAddress}, event.validation);
63 }
64 mCv.notify_one();
65 return ::ndk::ScopedAStatus::ok();
66 }
67
waitForPrivateDnsValidation(const std::string & serverAddr,int validation)68 bool UnsolicitedEventListener::waitForPrivateDnsValidation(const std::string& serverAddr,
69 int validation) {
70 const auto now = std::chrono::steady_clock::now();
71
72 std::unique_lock lock(mMutex);
73 ScopedLockAssertion assume_lock(mMutex);
74
75 // onPrivateDnsValidationEvent() might already be invoked. Search for the record first.
76 do {
77 if (findAndRemoveValidationRecord({mNetId, serverAddr}, validation)) return true;
78 } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);
79
80 // Timeout.
81 return false;
82 }
83
findAndRemoveValidationRecord(const ServerKey & key,int value)84 bool UnsolicitedEventListener::findAndRemoveValidationRecord(const ServerKey& key, int value) {
85 auto it = mValidationRecords.find(key);
86 if (it != mValidationRecords.end() && it->second == value) {
87 mValidationRecords.erase(it);
88 return true;
89 }
90 return false;
91 }
92
waitForNat64Prefix(int operation,const milliseconds & timeout)93 bool UnsolicitedEventListener::waitForNat64Prefix(int operation, const milliseconds& timeout) {
94 android::base::Timer t;
95 while (t.duration() < timeout) {
96 {
97 std::lock_guard lock(mMutex);
98 if ((operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED &&
99 !mNat64PrefixAddress.empty()) ||
100 (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED &&
101 mNat64PrefixAddress.empty())) {
102 mUnexpectedNat64PrefixUpdates--;
103 return true;
104 }
105 }
106 std::this_thread::sleep_for(kRetryIntervalMs);
107 }
108 return false;
109 }
110
popDnsHealthResult()111 Result<int> UnsolicitedEventListener::popDnsHealthResult() {
112 // Wait until the queue is not empty or timeout.
113 android::base::Timer t;
114 while (t.duration() < milliseconds{1000}) {
115 {
116 std::lock_guard lock(mMutex);
117 if (!mDnsHealthResultRecords.empty()) break;
118 }
119 std::this_thread::sleep_for(kRetryIntervalMs);
120 }
121
122 std::lock_guard lock(mMutex);
123 if (mDnsHealthResultRecords.empty()) return Error() << "Dns health result record is empty";
124
125 auto ret = mDnsHealthResultRecords.front();
126 mDnsHealthResultRecords.pop();
127 return ret;
128 }
129
130 } // namespace android::net::resolv::aidl
131