]>
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 | |
b4aac52a | 126 | value = make_pair(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 AT |
148 | int x=0; |
149 | while(cdb_findnext(&cdbf) > 0) { | |
150 | x++; | |
151 | unsigned int vpos = cdb_datapos(&d_cdb); | |
152 | unsigned int vlen = cdb_datalen(&d_cdb); | |
b4aac52a RG |
153 | std::string val; |
154 | val.resize(vlen); | |
90fe8ae6 RG |
155 | res = cdb_read(&d_cdb, &val[0], vlen, vpos); |
156 | if (res < 0) { | |
157 | throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(res)); | |
158 | } | |
b4aac52a | 159 | ret.push_back(std::move(val)); |
9153c7cf | 160 | } |
b4aac52a | 161 | |
9153c7cf | 162 | return ret; |
ddee6d08 | 163 | } |
90fe8ae6 | 164 | |
73e1f0c5 | 165 | bool CDB::keyExists(const string& key) |
90fe8ae6 RG |
166 | { |
167 | int ret = cdb_find(&d_cdb, key.c_str(), key.size()); | |
168 | if (ret < 0) { | |
169 | throw std::runtime_error("Error while looking up key '" + key + "' from CDB database: " + std::to_string(ret)); | |
170 | } | |
171 | if (ret == 0) { | |
172 | /* no such key */ | |
173 | return false; | |
174 | } | |
175 | ||
73e1f0c5 RG |
176 | return true; |
177 | } | |
178 | ||
179 | bool CDB::findOne(const string& key, string& value) | |
180 | { | |
181 | if (!keyExists(key)) { | |
182 | return false; | |
183 | } | |
184 | ||
90fe8ae6 RG |
185 | unsigned int vpos = cdb_datapos(&d_cdb); |
186 | unsigned int vlen = cdb_datalen(&d_cdb); | |
187 | value.resize(vlen); | |
73e1f0c5 | 188 | int ret = cdb_read(&d_cdb, &value[0], vlen, vpos); |
90fe8ae6 RG |
189 | if (ret < 0) { |
190 | throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(ret)); | |
191 | } | |
192 | ||
193 | return true; | |
194 | } | |
195 | ||
196 | CDBWriter::CDBWriter(int fd): d_fd(fd) | |
197 | { | |
198 | cdb_make_start(&d_cdbm, d_fd); | |
199 | } | |
200 | ||
201 | CDBWriter::~CDBWriter() | |
202 | { | |
203 | close(); | |
204 | } | |
205 | ||
206 | void CDBWriter::close() | |
207 | { | |
208 | if (d_fd >= 0) { | |
209 | cdb_make_finish(&d_cdbm); | |
210 | ::close(d_fd); | |
211 | d_fd = -1; | |
212 | } | |
213 | } | |
214 | ||
215 | bool CDBWriter::addEntry(const std::string& key, const std::string& value) | |
216 | { | |
217 | if (d_fd < 0) { | |
218 | throw std::runtime_error("Can't add an entry to a closed CDB database"); | |
219 | } | |
220 | ||
221 | int ret = cdb_make_add(&d_cdbm, key.c_str(), key.size(), value.c_str(), value.size()); | |
222 | if (ret != 0) { | |
223 | throw std::runtime_error("Error adding key '" + key + "' to CDB database: " + std::to_string(ret)); | |
224 | } | |
225 | ||
226 | return true; | |
227 | } |