Home | History | Annotate | Download | only in dns
      1 /*
      2  * Copyright (C) 2018 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 #ifndef _DNS_DNSTLSQUERYMAP_H
     18 #define _DNS_DNSTLSQUERYMAP_H
     19 
     20 #include <future>
     21 #include <map>
     22 #include <mutex>
     23 #include <vector>
     24 
     25 #include <android-base/thread_annotations.h>
     26 #include <netdutils/Slice.h>
     27 
     28 #include "dns/DnsTlsServer.h"
     29 
     30 namespace android {
     31 namespace net {
     32 
     33 using netdutils::Slice;
     34 
     35 // Keeps track of queries and responses.  This class matches responses with queries.
     36 // All methods are thread-safe and non-blocking.
     37 class DnsTlsQueryMap {
     38 public:
     39     struct Query {
     40         // The new ID number assigned to this query.
     41         uint16_t newId;
     42         // A query that has been passed to recordQuery(), with its original ID number.
     43         const Slice query;
     44     };
     45 
     46     typedef DnsTlsServer::Response Response;
     47     typedef DnsTlsServer::Result Result;
     48 
     49     struct QueryFuture {
     50         QueryFuture(Query query, std::future<Result> result) :
     51                 query(query), result(std::move(result)) {}
     52         Query query;
     53         // A future which will resolve to the result of this query.
     54         std::future<Result> result;
     55     };
     56 
     57     // Returns an object containing everything needed to complete processing of
     58     // this query, or null if the query could not be recorded.
     59     std::unique_ptr<QueryFuture> recordQuery(const Slice query);
     60 
     61     // Process a response, including a new ID.  If the response
     62     // is not recognized as matching any query, it will be ignored.
     63     void onResponse(std::vector<uint8_t> response);
     64 
     65     // Clear all map contents.  This causes all pending queries to resolve with failure.
     66     void clear();
     67 
     68     // Get all pending queries.  This returns a shallow copy, mostly for thread-safety.
     69     std::vector<Query> getAll();
     70 
     71     // Mark a query has having been retried.  If the query hits the retry limit, it will
     72     // be expired at the next call to cleanup.
     73     void markTried(uint16_t newId);
     74     void cleanup();
     75 
     76     // Returns true if there are no pending queries.
     77     bool empty();
     78 
     79 private:
     80     std::mutex mLock;
     81 
     82     struct QueryPromise {
     83         QueryPromise(Query query) : query(query) {}
     84         Query query;
     85         // Number of times the query has been tried.  Limited to kMaxTries.
     86         int tries = 0;
     87         // A promise whose future is returned by recordQuery()
     88         // It is fulfilled by onResponse().
     89         std::promise<Result> result;
     90     };
     91 
     92     // The maximum number of times we will send a query before abandoning it.
     93     static constexpr int kMaxTries = 3;
     94 
     95     // Outstanding queries by newId.
     96     std::map<uint16_t, QueryPromise> mQueries GUARDED_BY(mLock);
     97 
     98     // Get a "newId" number that is not currently in use.  Returns -1 if there are none.
     99     int32_t getFreeId() REQUIRES(mLock);
    100 
    101     // Fulfill the result with an error code.
    102     static void expire(QueryPromise* _Nonnull p);
    103 };
    104 
    105 }  // end of namespace net
    106 }  // end of namespace android
    107 
    108 #endif  // _DNS_DNSTLSQUERYMAP_H
    109