Refactor, prerequisite for DNS-over-TLS pipelining
This change should have no effect on behavior, but it divides functionality
out into classes in a way that will enable pipelining.
It also adds unit tests for the newly divided functionality.
Test: Unit and integration tests pass.
Bug: 63448521
Change-Id: I08948be304b7a3e4ba10f754ef58bd41db6824c4
diff --git a/server/dns/DnsTlsDispatcher.cpp b/server/dns/DnsTlsDispatcher.cpp
index 6fed9f0..be9c669 100644
--- a/server/dns/DnsTlsDispatcher.cpp
+++ b/server/dns/DnsTlsDispatcher.cpp
@@ -14,34 +14,53 @@
* limitations under the License.
*/
+#define LOG_TAG "DnsTlsDispatcher"
+//#define LOG_NDEBUG 0
+
#include "dns/DnsTlsDispatcher.h"
+#include "log/log.h"
+
namespace android {
namespace net {
+using netdutils::Slice;
+
// static
std::mutex DnsTlsDispatcher::sLock;
-std::map<DnsTlsDispatcher::Key, std::unique_ptr<DnsTlsDispatcher::Transport>> DnsTlsDispatcher::sStore;
DnsTlsTransport::Response DnsTlsDispatcher::query(const DnsTlsServer& server, unsigned mark,
- const uint8_t *query, size_t qlen, uint8_t *response, size_t limit, int *resplen) {
+ const Slice query,
+ const Slice ans, int *resplen) {
const Key key = std::make_pair(mark, server);
Transport* xport;
{
std::lock_guard<std::mutex> guard(sLock);
- auto it = sStore.find(key);
- if (it == sStore.end()) {
- xport = new Transport(server, mark);
- if (!xport->transport.initialize()) {
- return DnsTlsTransport::Response::internal_error;
- }
- sStore[key].reset(xport);
+ auto it = mStore.find(key);
+ if (it == mStore.end()) {
+ xport = new Transport(server, mark, mFactory.get());
+ mStore[key].reset(xport);
} else {
xport = it->second.get();
}
++xport->useCount;
}
- DnsTlsTransport::Response res = xport->transport.query(query, qlen, response, limit, resplen);
+ ALOGV("Sending query of length %zu", query.size());
+ auto result = xport->transport.query(query);
+ DnsTlsTransport::Response code = result.code;
+ if (code == DnsTlsTransport::Response::success) {
+ if (result.response.size() > ans.size()) {
+ ALOGV("Response too large: %zu > %zu", result.response.size(), ans.size());
+ code = DnsTlsTransport::Response::limit_error;
+ } else {
+ ALOGV("Got response successfully");
+ *resplen = result.response.size();
+ netdutils::copy(ans, netdutils::makeSlice(result.response));
+ }
+ } else {
+ ALOGV("Query failed: %u", (unsigned int)code);
+ }
+
auto now = std::chrono::steady_clock::now();
{
std::lock_guard<std::mutex> guard(sLock);
@@ -49,25 +68,27 @@
xport->lastUsed = now;
cleanup(now);
}
- return res;
+ return code;
}
+// This timeout effectively controls how long to keep SSL session tickets.
static constexpr std::chrono::minutes IDLE_TIMEOUT(5);
-std::chrono::time_point<std::chrono::steady_clock> DnsTlsDispatcher::sLastCleanup;
void DnsTlsDispatcher::cleanup(std::chrono::time_point<std::chrono::steady_clock> now) {
- if (now - sLastCleanup < IDLE_TIMEOUT) {
+ // To avoid scanning mStore after every query, return early if a cleanup has been
+ // performed recently.
+ if (now - mLastCleanup < IDLE_TIMEOUT) {
return;
}
- for (auto it = sStore.begin(); it != sStore.end(); ) {
+ for (auto it = mStore.begin(); it != mStore.end();) {
auto& s = it->second;
if (s->useCount == 0 && now - s->lastUsed > IDLE_TIMEOUT) {
- it = sStore.erase(it);
+ it = mStore.erase(it);
} else {
++it;
}
}
- sLastCleanup = now;
+ mLastCleanup = now;
}
-} // namespace net
-} // namespace android
+} // end of namespace net
+} // end of namespace android