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