• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.protocol},
63                                             event.validation);
64     }
65     mCv.notify_one();
66     return ::ndk::ScopedAStatus::ok();
67 }
68 
waitForPrivateDnsValidation(const std::string & serverAddr,int validation,int protocol)69 bool UnsolicitedEventListener::waitForPrivateDnsValidation(const std::string& serverAddr,
70                                                            int validation, int protocol) {
71     const auto now = std::chrono::steady_clock::now();
72 
73     std::unique_lock lock(mMutex);
74     ScopedLockAssertion assume_lock(mMutex);
75 
76     // onPrivateDnsValidationEvent() might already be invoked. Search for the record first.
77     do {
78         if (findAndRemoveValidationRecord({mNetId, serverAddr, protocol}, validation)) return true;
79     } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);
80 
81     // Timeout.
82     return false;
83 }
84 
findAndRemoveValidationRecord(const ServerKey & key,int value)85 bool UnsolicitedEventListener::findAndRemoveValidationRecord(const ServerKey& key, int value) {
86     auto it = mValidationRecords.find(key);
87     if (it != mValidationRecords.end() && it->second == value) {
88         mValidationRecords.erase(it);
89         return true;
90     }
91     return false;
92 }
93 
waitForNat64Prefix(int operation,const milliseconds & timeout)94 bool UnsolicitedEventListener::waitForNat64Prefix(int operation, const milliseconds& timeout) {
95     android::base::Timer t;
96     while (t.duration() < timeout) {
97         {
98             std::lock_guard lock(mMutex);
99             if ((operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED &&
100                  !mNat64PrefixAddress.empty()) ||
101                 (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED &&
102                  mNat64PrefixAddress.empty())) {
103                 mUnexpectedNat64PrefixUpdates--;
104                 return true;
105             }
106         }
107         std::this_thread::sleep_for(kRetryIntervalMs);
108     }
109     return false;
110 }
111 
popDnsHealthResult()112 Result<int> UnsolicitedEventListener::popDnsHealthResult() {
113     // Wait until the queue is not empty or timeout.
114     android::base::Timer t;
115     while (t.duration() < milliseconds{1000}) {
116         {
117             std::lock_guard lock(mMutex);
118             if (!mDnsHealthResultRecords.empty()) break;
119         }
120         std::this_thread::sleep_for(kRetryIntervalMs);
121     }
122 
123     std::lock_guard lock(mMutex);
124     if (mDnsHealthResultRecords.empty()) return Error() << "Dns health result record is empty";
125 
126     auto ret = mDnsHealthResultRecords.front();
127     mDnsHealthResultRecords.pop();
128     return ret;
129 }
130 
131 }  // namespace android::net::resolv::aidl
132