1 /* 2 * Copyright (C) 2017 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_DNSTLSDISPATCHER_H 18 #define _DNS_DNSTLSDISPATCHER_H 19 20 #include <list> 21 #include <map> 22 #include <memory> 23 #include <mutex> 24 25 #include <android-base/thread_annotations.h> 26 #include <netdutils/Slice.h> 27 28 #include "DnsTlsServer.h" 29 #include "DnsTlsTransport.h" 30 #include "IDnsTlsSocketFactory.h" 31 32 namespace android { 33 namespace net { 34 35 // This is a singleton class that manages the collection of active DnsTlsTransports. 36 // Queries made here are dispatched to an existing or newly constructed DnsTlsTransport. 37 class DnsTlsDispatcher { 38 public: 39 // Default constructor. 40 DnsTlsDispatcher(); 41 42 // Constructor with dependency injection for testing. DnsTlsDispatcher(std::unique_ptr<IDnsTlsSocketFactory> factory)43 explicit DnsTlsDispatcher(std::unique_ptr<IDnsTlsSocketFactory> factory) 44 : mFactory(std::move(factory)) {} 45 46 // Enqueues |query| for resolution via the given |tlsServers| on the 47 // network indicated by |mark|; writes the response into |ans|, and stores 48 // the count of bytes written in |resplen|. Returns a success or error code. 49 // The order in which servers from |tlsServers| are queried may not be the 50 // order passed in by the caller. 51 DnsTlsTransport::Response query(const std::list<DnsTlsServer>& tlsServers, unsigned mark, 52 const netdutils::Slice query, const netdutils::Slice ans, 53 int* _Nonnull resplen); 54 55 // Given a |query|, sends it to the server on the network indicated by |mark|, 56 // and writes the response into |ans|, and indicates 57 // the number of bytes written in |resplen|. Returns a success or error code. 58 DnsTlsTransport::Response query(const DnsTlsServer& server, unsigned mark, 59 const netdutils::Slice query, const netdutils::Slice ans, 60 int* _Nonnull resplen); 61 62 private: 63 // This lock is static so that it can be used to annotate the Transport struct. 64 // DnsTlsDispatcher is a singleton in practice, so making this static does not change 65 // the locking behavior. 66 static std::mutex sLock; 67 68 // Key = <mark, server> 69 typedef std::pair<unsigned, const DnsTlsServer> Key; 70 71 // Transport is a thin wrapper around DnsTlsTransport, adding reference counting and 72 // usage monitoring so we can expire idle sessions from the cache. 73 struct Transport { TransportTransport74 Transport(const DnsTlsServer& server, unsigned mark, IDnsTlsSocketFactory* _Nonnull factory) 75 : transport(server, mark, factory) {} 76 // DnsTlsTransport is thread-safe, so it doesn't need to be guarded. 77 DnsTlsTransport transport; 78 // This use counter and timestamp are used to ensure that only idle sessions are 79 // destroyed. 80 int useCount GUARDED_BY(sLock) = 0; 81 // lastUsed is only guaranteed to be meaningful after useCount is decremented to zero. 82 std::chrono::time_point<std::chrono::steady_clock> lastUsed GUARDED_BY(sLock); 83 }; 84 85 // Cache of reusable DnsTlsTransports. Transports stay in cache as long as 86 // they are in use and for a few minutes after. 87 // The key is a (netid, server) pair. The netid is first for lexicographic comparison speed. 88 std::map<Key, std::unique_ptr<Transport>> mStore GUARDED_BY(sLock); 89 90 // The last time we did a cleanup. For efficiency, we only perform a cleanup once every 91 // few minutes. 92 std::chrono::time_point<std::chrono::steady_clock> mLastCleanup GUARDED_BY(sLock); 93 94 // Drop any cache entries whose useCount is zero and which have not been used recently. 95 // This function performs a linear scan of mStore. 96 void cleanup(std::chrono::time_point<std::chrono::steady_clock> now) REQUIRES(sLock); 97 98 // Return a sorted list of DnsTlsServers in preference order. 99 std::list<DnsTlsServer> getOrderedServerList(const std::list<DnsTlsServer>& tlsServers, 100 unsigned mark) const; 101 102 // Trivial factory for DnsTlsSockets. Dependency injection is only used for testing. 103 std::unique_ptr<IDnsTlsSocketFactory> mFactory; 104 }; 105 106 } // end of namespace net 107 } // end of namespace android 108 109 #endif // _DNS_DNSTLSDISPATCHER_H 110