]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdistdist/dnsdist-kvs.cc
dnsdist: Wrap pthread_ objects
[thirdparty/pdns.git] / pdns / dnsdistdist / dnsdist-kvs.cc
CommitLineData
f441962a
RG
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "dnsdist-kvs.hh"
24#include "dolog.hh"
25
e5407513
RG
26#include <sys/stat.h>
27
14de749b 28std::vector<std::string> KeyValueLookupKeySourceIP::getKeys(const ComboAddress& addr)
e56dbccd
RG
29{
30 std::vector<std::string> result;
31
14de749b
RG
32 if (addr.sin4.sin_family == AF_INET) {
33 result.emplace_back(reinterpret_cast<const char*>(&addr.sin4.sin_addr.s_addr), sizeof(addr.sin4.sin_addr.s_addr));
e56dbccd 34 }
14de749b
RG
35 else if (addr.sin4.sin_family == AF_INET6) {
36 result.emplace_back(reinterpret_cast<const char*>(&addr.sin6.sin6_addr.s6_addr), sizeof(addr.sin6.sin6_addr.s6_addr));
e56dbccd
RG
37 }
38
39 return result;
40}
41
42std::vector<std::string> KeyValueLookupKeySuffix::getKeys(const DNSName& qname)
43{
44 if (qname.empty() || qname.isRoot()) {
45 return {};
46 }
47
48 auto lowerQName = qname.makeLowerCase();
b5b3fc9b
RG
49 size_t labelsCount = lowerQName.countLabels();
50 if (d_minLabels != 0) {
51 if (labelsCount < d_minLabels) {
52 return {};
53 }
54 labelsCount -= (d_minLabels - 1);
55 }
56
e56dbccd 57 std::vector<std::string> result;
b5b3fc9b 58 result.reserve(labelsCount);
e56dbccd
RG
59
60 while(!lowerQName.isRoot()) {
752db0de 61 result.emplace_back(d_wireFormat ? lowerQName.toDNSString() : lowerQName.toStringRootDot());
b5b3fc9b
RG
62 labelsCount--;
63 if (!lowerQName.chopOff() || labelsCount == 0) {
e56dbccd
RG
64 break;
65 }
66 }
67
68 return result;
69}
70
f441962a
RG
71#ifdef HAVE_LMDB
72
90fe8ae6 73bool LMDBKVStore::getValue(const std::string& key, std::string& value)
f441962a 74{
f441962a
RG
75 try {
76 auto transaction = d_env.getROTransaction();
d76cdfe9 77 auto dbi = transaction->openDB(d_dbName, 0);
4778cfd2 78 MDBOutVal result;
d76cdfe9 79 int rc = transaction->get(dbi, MDBInVal(key), result);
f441962a 80 if (rc == 0) {
4778cfd2 81 value = result.get<std::string>();
90fe8ae6 82 return true;
f441962a
RG
83 }
84 else if (rc == MDB_NOTFOUND) {
90fe8ae6 85 return false;
f441962a
RG
86 }
87 }
88 catch(const std::exception& e) {
e56dbccd 89 warnlog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
f441962a 90 }
90fe8ae6 91 return false;
f441962a
RG
92}
93
73e1f0c5
RG
94bool LMDBKVStore::keyExists(const std::string& key)
95{
73e1f0c5
RG
96 try {
97 auto transaction = d_env.getROTransaction();
d76cdfe9 98 auto dbi = transaction->openDB(d_dbName, 0);
4778cfd2 99 MDBOutVal result;
d76cdfe9 100 int rc = transaction->get(dbi, MDBInVal(key), result);
73e1f0c5
RG
101 if (rc == 0) {
102 return true;
103 }
104 else if (rc == MDB_NOTFOUND) {
105 return false;
106 }
107 }
108 catch(const std::exception& e) {
109 warnlog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
110 }
111 return false;
112}
113
f441962a 114#endif /* HAVE_LMDB */
90fe8ae6
RG
115
116#ifdef HAVE_CDB
117
e5407513
RG
118CDBKVStore::CDBKVStore(const std::string& fname, time_t refreshDelay): d_fname(fname), d_refreshDelay(refreshDelay)
119{
e5407513
RG
120 d_refreshing.clear();
121
122 time_t now = time(nullptr);
123 if (d_refreshDelay > 0) {
124 d_nextCheck = now + d_refreshDelay;
125 }
126
127 refreshDBIfNeeded(now);
128}
129
040793d4 130CDBKVStore::~CDBKVStore() {
040793d4
OM
131}
132
14de749b
RG
133bool CDBKVStore::reload(const struct stat& st)
134{
0d1510ae 135 auto newCDB = std::unique_ptr<CDB>(new CDB(d_fname));
14de749b
RG
136 {
137 WriteLock wl(&d_lock);
138 d_cdb = std::move(newCDB);
139 }
140 d_mtime = st.st_mtime;
141 return true;
142}
143
144bool CDBKVStore::reload()
145{
146 struct stat st;
147 if (stat(d_fname.c_str(), &st) == 0) {
148 return reload(st);
149 }
150 else {
151 warnlog("Error while retrieving the last modification time of CDB database '%s': %s", d_fname, stringerror());
152 return false;
153 }
154}
155
e5407513
RG
156void CDBKVStore::refreshDBIfNeeded(time_t now)
157{
158 if (d_refreshing.test_and_set()) {
159 /* someone else is already refreshing */
160 return;
161 }
162
163 try {
164 struct stat st;
165 if (stat(d_fname.c_str(), &st) == 0) {
166 if (st.st_mtime > d_mtime) {
14de749b 167 reload(st);
e5407513
RG
168 }
169 }
170 else {
171 warnlog("Error while retrieving the last modification time of CDB database '%s': %s", d_fname, stringerror());
172 }
173 d_nextCheck = now + d_refreshDelay;
75ee3a9a 174 d_refreshing.clear();
e5407513
RG
175 }
176 catch(...) {
177 d_refreshing.clear();
178 throw;
179 }
180}
181
90fe8ae6
RG
182bool CDBKVStore::getValue(const std::string& key, std::string& value)
183{
e5407513
RG
184 time_t now = time(nullptr);
185
90fe8ae6 186 try {
e5407513
RG
187 if (d_nextCheck != 0 && now >= d_nextCheck) {
188 refreshDBIfNeeded(now);
189 }
190
191 {
192 ReadLock rl(&d_lock);
193 if (d_cdb && d_cdb->findOne(key, value)) {
194 return true;
195 }
90fe8ae6
RG
196 }
197 }
198 catch(const std::exception& e) {
470f3339 199 warnlog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
90fe8ae6
RG
200 }
201 return false;
202}
203
73e1f0c5
RG
204bool CDBKVStore::keyExists(const std::string& key)
205{
206 time_t now = time(nullptr);
207
208 try {
209 if (d_nextCheck != 0 && now >= d_nextCheck) {
210 refreshDBIfNeeded(now);
211 }
212
213 {
214 ReadLock rl(&d_lock);
215 if (!d_cdb) {
216 return false;
217 }
218
219 return d_cdb->keyExists(key);
220 }
221 }
222 catch(const std::exception& e) {
470f3339 223 warnlog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
73e1f0c5
RG
224 }
225 return false;
226}
227
90fe8ae6 228#endif /* HAVE_CDB */