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 "doh_frontend.h"
18
19 #define LOG_TAG "DohFrontend"
20
21 #include <thread>
22
23 #include <android-base/chrono_utils.h>
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <gtest/gtest.h>
27
28 #include "dns_tls_certificate.h"
29
30 using std::chrono::milliseconds;
31
32 namespace test {
33
34 constexpr milliseconds kEventTimeoutMs{5000};
35 constexpr milliseconds kRetryIntervalMs{20};
36
~DohFrontend()37 DohFrontend::~DohFrontend() {
38 if (mRustDoh) {
39 stopServer();
40 rust::frontend_delete(mRustDoh);
41 }
42 }
43
startServer()44 bool DohFrontend::startServer() {
45 std::lock_guard guard(mMutex);
46 if (mRustDoh == nullptr) {
47 mRustDoh = rust::frontend_new(mAddress.c_str(), mService.c_str(), mBackendAddress.c_str(),
48 mBackendService.c_str());
49 if (mRustDoh == nullptr) {
50 LOG(ERROR) << "Failed to create rust DoH frontend";
51 return false;
52 }
53 }
54
55 rust::frontend_set_certificate(mRustDoh, kCertificate);
56 rust::frontend_set_private_key(mRustDoh, kPrivatekey);
57
58 return rust::frontend_start(mRustDoh);
59 }
60
stopServer()61 bool DohFrontend::stopServer() {
62 std::lock_guard guard(mMutex);
63 if (!mRustDoh) return false;
64
65 rust::frontend_stop(mRustDoh);
66 return true;
67 }
68
queries() const69 int DohFrontend::queries() const {
70 std::lock_guard guard(mMutex);
71 if (!mRustDoh) return 0;
72
73 rust::Stats stats;
74 rust::frontend_stats(mRustDoh, &stats);
75 return stats.queries_received;
76 }
77
connections() const78 int DohFrontend::connections() const {
79 std::lock_guard guard(mMutex);
80 if (!mRustDoh) return 0;
81
82 rust::Stats stats;
83 rust::frontend_stats(mRustDoh, &stats);
84 return stats.connections_accepted;
85 }
86
aliveConnections() const87 int DohFrontend::aliveConnections() const {
88 std::lock_guard guard(mMutex);
89 if (!mRustDoh) return 0;
90
91 rust::Stats stats;
92 rust::frontend_stats(mRustDoh, &stats);
93 return stats.alive_connections;
94 }
95
resumedConnections() const96 int DohFrontend::resumedConnections() const {
97 std::lock_guard guard(mMutex);
98 if (!mRustDoh) return 0;
99
100 rust::Stats stats;
101 rust::frontend_stats(mRustDoh, &stats);
102 return stats.resumed_connections;
103 }
104
clearQueries()105 void DohFrontend::clearQueries() {
106 std::lock_guard guard(mMutex);
107 if (mRustDoh) {
108 frontend_stats_clear_queries(mRustDoh);
109
110 // Because frontend_stats_clear_queries() is asynchronous, query the stat here to ensure
111 // that mRustDoh reset the query count before clearQueries() returns.
112 rust::Stats stats;
113 rust::frontend_stats(mRustDoh, &stats);
114 if (stats.queries_received != 0) {
115 LOG(ERROR) << "queries_received is not 0";
116 }
117 }
118 }
119
setMaxIdleTimeout(uint64_t value)120 bool DohFrontend::setMaxIdleTimeout(uint64_t value) {
121 std::lock_guard guard(mMutex);
122 if (!mRustDoh) return false;
123
124 frontend_set_max_idle_timeout(mRustDoh, value);
125 return true;
126 }
127
setMaxBufferSize(uint64_t value)128 bool DohFrontend::setMaxBufferSize(uint64_t value) {
129 std::lock_guard guard(mMutex);
130 if (!mRustDoh) return false;
131
132 frontend_set_max_buffer_size(mRustDoh, value);
133 return true;
134 }
135
setMaxStreamsBidi(uint64_t value)136 bool DohFrontend::setMaxStreamsBidi(uint64_t value) {
137 std::lock_guard guard(mMutex);
138 if (!mRustDoh) return false;
139
140 frontend_set_max_streams_bidi(mRustDoh, value);
141 return true;
142 }
143
block_sending(bool block)144 bool DohFrontend::block_sending(bool block) {
145 std::lock_guard guard(mMutex);
146 if (!mRustDoh) return false;
147
148 frontend_block_sending(mRustDoh, block);
149 return true;
150 }
151
waitForAllClientsDisconnected() const152 bool DohFrontend::waitForAllClientsDisconnected() const {
153 android::base::Timer t;
154 while (t.duration() < kEventTimeoutMs) {
155 if (aliveConnections() == 0) return true;
156 std::this_thread::sleep_for(kRetryIntervalMs);
157 }
158 return false;
159 }
160
161 } // namespace test
162