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 return rust::frontend_stop(mRustDoh);
66 }
67
queries() const68 int DohFrontend::queries() const {
69 std::lock_guard guard(mMutex);
70 if (!mRustDoh) return 0;
71
72 rust::Stats stats;
73 rust::frontend_stats(mRustDoh, &stats);
74 return stats.queries_received;
75 }
76
connections() const77 int DohFrontend::connections() const {
78 std::lock_guard guard(mMutex);
79 if (!mRustDoh) return 0;
80
81 rust::Stats stats;
82 rust::frontend_stats(mRustDoh, &stats);
83 return stats.connections_accepted;
84 }
85
aliveConnections() const86 int DohFrontend::aliveConnections() const {
87 std::lock_guard guard(mMutex);
88 if (!mRustDoh) return 0;
89
90 rust::Stats stats;
91 rust::frontend_stats(mRustDoh, &stats);
92 return stats.alive_connections;
93 }
94
resumedConnections() const95 int DohFrontend::resumedConnections() const {
96 std::lock_guard guard(mMutex);
97 if (!mRustDoh) return 0;
98
99 rust::Stats stats;
100 rust::frontend_stats(mRustDoh, &stats);
101 return stats.resumed_connections;
102 }
103
earlyDataConnections() const104 int DohFrontend::earlyDataConnections() const {
105 std::lock_guard guard(mMutex);
106 if (!mRustDoh) return 0;
107
108 rust::Stats stats;
109 rust::frontend_stats(mRustDoh, &stats);
110 return stats.early_data_connections;
111 }
112
clearQueries()113 void DohFrontend::clearQueries() {
114 std::lock_guard guard(mMutex);
115 if (mRustDoh) {
116 frontend_stats_clear_queries(mRustDoh);
117
118 // Because frontend_stats_clear_queries() is asynchronous, query the stat here to ensure
119 // that mRustDoh reset the query count before clearQueries() returns.
120 rust::Stats stats;
121 rust::frontend_stats(mRustDoh, &stats);
122 if (stats.queries_received != 0) {
123 LOG(ERROR) << "queries_received is not 0";
124 }
125 }
126 }
127
setMaxIdleTimeout(uint64_t value)128 bool DohFrontend::setMaxIdleTimeout(uint64_t value) {
129 std::lock_guard guard(mMutex);
130 if (!mRustDoh) return false;
131
132 return frontend_set_max_idle_timeout(mRustDoh, value);
133 }
134
setMaxBufferSize(uint64_t value)135 bool DohFrontend::setMaxBufferSize(uint64_t value) {
136 std::lock_guard guard(mMutex);
137 if (!mRustDoh) return false;
138
139 return frontend_set_max_buffer_size(mRustDoh, value);
140 }
141
setMaxStreamsBidi(uint64_t value)142 bool DohFrontend::setMaxStreamsBidi(uint64_t value) {
143 std::lock_guard guard(mMutex);
144 if (!mRustDoh) return false;
145
146 return frontend_set_max_streams_bidi(mRustDoh, value);
147 }
148
block_sending(bool block)149 bool DohFrontend::block_sending(bool block) {
150 std::lock_guard guard(mMutex);
151 if (!mRustDoh) return false;
152
153 return frontend_block_sending(mRustDoh, block);
154 }
155
setResetStreamId(uint64_t value)156 bool DohFrontend::setResetStreamId(uint64_t value) {
157 std::lock_guard guard(mMutex);
158 if (!mRustDoh) return false;
159
160 return frontend_set_reset_stream_id(mRustDoh, value);
161 }
162
waitForAllClientsDisconnected() const163 bool DohFrontend::waitForAllClientsDisconnected() const {
164 android::base::Timer t;
165 while (t.duration() < kEventTimeoutMs) {
166 if (aliveConnections() == 0) return true;
167 std::this_thread::sleep_for(kRetryIntervalMs);
168 }
169 return false;
170 }
171
172 } // namespace test
173