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