]>
Commit | Line | Data |
---|---|---|
12471842 PL |
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 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
ddee6d08 | 25 | |
b4aac52a RG |
26 | #include <sys/types.h> |
27 | #include <sys/stat.h> | |
28 | #include <fcntl.h> | |
29 | #include <unistd.h> | |
30 | ||
31 | #include "cdb.hh" | |
ddee6d08 PD |
32 | |
33 | CDB::CDB(const string &cdbfile) | |
34 | { | |
9153c7cf AT |
35 | d_fd = open(cdbfile.c_str(), O_RDONLY); |
36 | if (d_fd < 0) | |
37 | { | |
90fe8ae6 | 38 | throw std::runtime_error("Failed to open cdb database file '"+cdbfile+"': " + stringerror()); |
9153c7cf AT |
39 | } |
40 | ||
d9b78c0a | 41 | memset(&d_cdbf,0,sizeof(struct cdb_find)); |
9153c7cf AT |
42 | int cdbinit = cdb_init(&d_cdb, d_fd); |
43 | if (cdbinit < 0) | |
44 | { | |
b4aac52a RG |
45 | close(d_fd); |
46 | d_fd = -1; | |
90fe8ae6 | 47 | throw std::runtime_error("Failed to initialize cdb structure for database '+cdbfile+': '" + std::to_string(cdbinit) + "'"); |
9153c7cf | 48 | } |
ddee6d08 PD |
49 | } |
50 | ||
51 | CDB::~CDB() { | |
9153c7cf AT |
52 | cdb_free(&d_cdb); |
53 | close(d_fd); | |
ddee6d08 PD |
54 | } |
55 | ||
56 | int CDB::searchKey(const string &key) { | |
9153c7cf | 57 | d_searchType = SearchKey; |
ddee6d08 | 58 | |
9153c7cf AT |
59 | // A 'bug' in tinycdb (the lib used for reading the CDB files) means we have to copy the key because the cdb_find struct |
60 | // keeps a pointer to it. | |
b4aac52a RG |
61 | d_key = key; |
62 | return cdb_findinit(&d_cdbf, &d_cdb, d_key.c_str(), d_key.size()); | |
ddee6d08 PD |
63 | } |
64 | ||
65 | bool CDB::searchSuffix(const string &key) { | |
9153c7cf | 66 | d_searchType = SearchSuffix; |
ddee6d08 | 67 | |
9153c7cf | 68 | //See CDB::searchKey() |
b4aac52a | 69 | d_key = key; |
ddee6d08 | 70 | |
9153c7cf | 71 | // We are ok with a search on things, but we do want to know if a record with that key exists......... |
b4aac52a | 72 | bool hasDomain = (cdb_find(&d_cdb, d_key.c_str(), d_key.size()) == 1); |
9153c7cf AT |
73 | if (hasDomain) { |
74 | cdb_seqinit(&d_seqPtr, &d_cdb); | |
75 | } | |
ddee6d08 | 76 | |
9153c7cf | 77 | return hasDomain; |
ddee6d08 PD |
78 | } |
79 | ||
80 | void CDB::searchAll() { | |
9153c7cf AT |
81 | d_searchType = SearchAll; |
82 | cdb_seqinit(&d_seqPtr, &d_cdb); | |
ddee6d08 PD |
83 | } |
84 | ||
85 | bool CDB::moveToNext() { | |
9153c7cf AT |
86 | int hasNext = 0; |
87 | if (d_searchType == SearchKey) { | |
88 | hasNext = cdb_findnext(&d_cdbf); | |
89 | } else { | |
90 | hasNext = cdb_seqnext(&d_seqPtr, &d_cdb); | |
91 | } | |
92 | return (hasNext > 0); | |
ddee6d08 PD |
93 | } |
94 | ||
95 | bool CDB::readNext(pair<string, string> &value) { | |
9153c7cf AT |
96 | while (moveToNext()) { |
97 | unsigned int pos; | |
98 | unsigned int len; | |
99 | ||
100 | pos = cdb_keypos(&d_cdb); | |
101 | len = cdb_keylen(&d_cdb); | |
102 | ||
b4aac52a RG |
103 | std::string key; |
104 | key.resize(len); | |
90fe8ae6 RG |
105 | int ret = cdb_read(&d_cdb, &key[0], len, pos); |
106 | if (ret < 0) { | |
107 | throw std::runtime_error("Error while reading key for key '" + key + "' from CDB database: " + std::to_string(ret)); | |
108 | } | |
9153c7cf AT |
109 | |
110 | if (d_searchType == SearchSuffix) { | |
b4aac52a RG |
111 | char *p = strstr(const_cast<char*>(key.c_str()), d_key.c_str()); |
112 | if (p == nullptr) { | |
9153c7cf AT |
113 | continue; |
114 | } | |
115 | } | |
9153c7cf AT |
116 | |
117 | pos = cdb_datapos(&d_cdb); | |
118 | len = cdb_datalen(&d_cdb); | |
b4aac52a RG |
119 | std::string val; |
120 | val.resize(len); | |
90fe8ae6 RG |
121 | ret = cdb_read(&d_cdb, &val[0], len, pos); |
122 | if (ret < 0) { | |
123 | throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(ret)); | |
124 | } | |
9153c7cf | 125 | |
e32a8d46 | 126 | value = {std::move(key), std::move(val)}; |
9153c7cf AT |
127 | return true; |
128 | } | |
b4aac52a | 129 | |
9153c7cf AT |
130 | // We're done searching, so we can clean up d_key |
131 | if (d_searchType != SearchAll) { | |
b4aac52a | 132 | d_key.clear(); |
9153c7cf | 133 | } |
b4aac52a | 134 | |
9153c7cf | 135 | return false; |
ddee6d08 PD |
136 | } |
137 | ||
ddee6d08 PD |
138 | vector<string> CDB::findall(string &key) |
139 | { | |
9153c7cf AT |
140 | vector<string> ret; |
141 | struct cdb_find cdbf; | |
142 | ||
90fe8ae6 RG |
143 | int res = cdb_findinit(&cdbf, &d_cdb, key.c_str(), key.size()); |
144 | if (res < 0) { | |
145 | throw std::runtime_error("Error looking up key '" + key + "' from CDB database: " + std::to_string(res)); | |
146 | } | |
147 | ||
9153c7cf | 148 | while(cdb_findnext(&cdbf) > 0) { |
9153c7cf AT |
149 | unsigned int vpos = cdb_datapos(&d_cdb); |
150 | unsigned int vlen = cdb_datalen(&d_cdb); | |
b4aac52a RG |
151 | std::string val; |
152 | val.resize(vlen); | |
90fe8ae6 RG |
153 | res = cdb_read(&d_cdb, &val[0], vlen, vpos); |
154 | if (res < 0) { | |
155 | throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(res)); | |
156 | } | |
b4aac52a | 157 | ret.push_back(std::move(val)); |
9153c7cf | 158 | } |
b4aac52a | 159 | |
9153c7cf | 160 | return ret; |
ddee6d08 | 161 | } |
90fe8ae6 | 162 | |
73e1f0c5 | 163 | bool CDB::keyExists(const string& key) |
90fe8ae6 RG |
164 | { |
165 | int ret = cdb_find(&d_cdb, key.c_str(), key.size()); | |
166 | if (ret < 0) { | |
167 | throw std::runtime_error("Error while looking up key '" + key + "' from CDB database: " + std::to_string(ret)); | |
168 | } | |
169 | if (ret == 0) { | |
170 | /* no such key */ | |
171 | return false; | |
172 | } | |
173 | ||
73e1f0c5 RG |
174 | return true; |
175 | } | |
176 | ||
177 | bool CDB::findOne(const string& key, string& value) | |
178 | { | |
179 | if (!keyExists(key)) { | |
180 | return false; | |
181 | } | |
182 | ||
90fe8ae6 RG |
183 | unsigned int vpos = cdb_datapos(&d_cdb); |
184 | unsigned int vlen = cdb_datalen(&d_cdb); | |
185 | value.resize(vlen); | |
73e1f0c5 | 186 | int ret = cdb_read(&d_cdb, &value[0], vlen, vpos); |
90fe8ae6 RG |
187 | if (ret < 0) { |
188 | throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(ret)); | |
189 | } | |
190 | ||
191 | return true; | |
192 | } | |
193 | ||
194 | CDBWriter::CDBWriter(int fd): d_fd(fd) | |
195 | { | |
196 | cdb_make_start(&d_cdbm, d_fd); | |
197 | } | |
198 | ||
199 | CDBWriter::~CDBWriter() | |
200 | { | |
201 | close(); | |
202 | } | |
203 | ||
204 | void CDBWriter::close() | |
205 | { | |
206 | if (d_fd >= 0) { | |
207 | cdb_make_finish(&d_cdbm); | |
208 | ::close(d_fd); | |
209 | d_fd = -1; | |
210 | } | |
211 | } | |
212 | ||
213 | bool CDBWriter::addEntry(const std::string& key, const std::string& value) | |
214 | { | |
215 | if (d_fd < 0) { | |
216 | throw std::runtime_error("Can't add an entry to a closed CDB database"); | |
217 | } | |
218 | ||
219 | int ret = cdb_make_add(&d_cdbm, key.c_str(), key.size(), value.c_str(), value.size()); | |
220 | if (ret != 0) { | |
221 | throw std::runtime_error("Error adding key '" + key + "' to CDB database: " + std::to_string(ret)); | |
222 | } | |
223 | ||
224 | return true; | |
225 | } |