blob: 7a955b5b070b60867960b0e75d310662f7ec7876 [file] [log] [blame]
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California
4 *
5 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
6 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
7 *
8 * ndn-group-encrypt is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-group-encrypt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-group-encrypt, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
20 */
21
22#include "group-manager-db.hpp"
23
24#include <sqlite3.h>
25#include <boost/filesystem.hpp>
26#include <ndn-cxx/util/sqlite3-statement.hpp>
27#include <ndn-cxx/security/identity-certificate.hpp>
28
29namespace ndn {
30namespace gep {
31
32using util::Sqlite3Statement;
33
34static const std::string INITIALIZATION =
35 "CREATE TABLE IF NOT EXISTS \n"
36 " schedules( \n"
37 " schedule_id INTEGER PRIMARY KEY, \n"
38 " schedule_name TEXT NOT NULL, \n"
39 " schedule BLOB NOT NULL \n"
40 " ); \n"
41 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
42 " scheduleNameIndex ON schedules(schedule_name); \n"
43 " \n"
44 "CREATE TABLE IF NOT EXISTS \n"
45 " members( \n"
46 " member_id INTEGER PRIMARY KEY, \n"
47 " schedule_id INTEGER NOT NULL, \n"
48 " member_name BLOB NOT NULL, \n"
49 " member_cert BLOB NOT NULL, \n"
50 " FOREIGN KEY(schedule_id) \n"
51 " REFERENCES schedules(schedule_id) \n"
52 " ON DELETE CASCADE \n"
53 " ON UPDATE CASCADE \n"
54 " ); \n"
55 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
56 " memNameIndex ON members(member_name); \n";
57
58class GroupManagerDB::Impl
59{
60public:
61 Impl(const std::string& dbDir)
62 {
63 // open Database
64
65 int result = sqlite3_open_v2(dbDir.c_str(), &m_database,
66 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
67#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
68 "unix-dotfile"
69#else
70 nullptr
71#endif
72 );
73
74 if (result != SQLITE_OK)
75 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be opened/created: " + dbDir));
76
77 // enable foreign key
78 sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
79
80 // initialize database specific tables
81 char* errorMessage = nullptr;
82 result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
83 if (result != SQLITE_OK && errorMessage != nullptr) {
84 sqlite3_free(errorMessage);
85 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be initialized"));
86 }
87 }
88
89 ~Impl()
90 {
91 sqlite3_close(m_database);
92 }
93
94 int
95 getScheduleId(const std::string& name) const
96 {
97 Sqlite3Statement statement(m_database,
98 "SELECT schedule_id FROM schedules WHERE schedule_name=?");
99 statement.bind(1, name, SQLITE_TRANSIENT);
100
101 int result = -1;
102 if (statement.step() == SQLITE_ROW)
103 result = statement.getInt(0);
104 return result;
105 }
106
107public:
108 sqlite3* m_database;
109};
110
111GroupManagerDB::GroupManagerDB(const std::string& dbDir)
112 : m_impl(new Impl(dbDir))
113{
114}
115
116GroupManagerDB::~GroupManagerDB() = default;
117
118bool
119GroupManagerDB::hasSchedule(const std::string& name) const
120{
121 Sqlite3Statement statement(m_impl->m_database,
122 "SELECT schedule_id FROM schedules where schedule_name=?");
123 statement.bind(1, name, SQLITE_TRANSIENT);
124 return (statement.step() == SQLITE_ROW);
125}
126
127std::list<std::string>
128GroupManagerDB::listAllScheduleNames() const
129{
130 std::list<std::string> result;
131 Sqlite3Statement statement(m_impl->m_database,
132 "SELECT schedule_name FROM schedules");
133
134 result.clear();
135 while (statement.step() == SQLITE_ROW) {
136 result.push_back(statement.getString(0));
137 }
138 return result;
139}
140
141Schedule
142GroupManagerDB::getSchedule(const std::string& name) const
143{
144 Sqlite3Statement statement(m_impl->m_database,
145 "SELECT schedule FROM schedules where schedule_name=?");
146 statement.bind(1, name, SQLITE_TRANSIENT);
147
148 Schedule result;
149 if (statement.step() == SQLITE_ROW) {
150 result.wireDecode(statement.getBlock(0));
151 }
152 else {
153 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
154 }
155 return result;
156}
157
158std::map<Name, Data>
159GroupManagerDB::getScheduleMembers(const std::string& name) const
160{
161 std::map<Name, Data> result;
162 Sqlite3Statement statement(m_impl->m_database,
163 "SELECT member_name, member_cert\
164 FROM members JOIN schedules\
165 ON members.schedule_id=schedules.schedule_id\
166 WHERE schedule_name=?");
167 statement.bind(1, name, SQLITE_TRANSIENT);
168
169 result.clear();
170 while (statement.step() == SQLITE_ROW) {
171 result.insert(std::pair<Name, Data>(Name(statement.getBlock(0)),
172 Data(statement.getBlock(1))));
173 }
174 return result;
175}
176
177void
178GroupManagerDB::addSchedule(const std::string& name, const Schedule& schedule)
179{
180 BOOST_ASSERT(name.length() != 0);
181
182 Sqlite3Statement statement(m_impl->m_database,
183 "INSERT INTO schedules (schedule_name, schedule)\
184 values (?, ?)");
185 statement.bind(1, name, SQLITE_TRANSIENT);
186 statement.bind(2, schedule.wireEncode(), SQLITE_TRANSIENT);
187 if (statement.step() != SQLITE_DONE)
188 BOOST_THROW_EXCEPTION(Error("Cannot add the schedule to database"));
189}
190
191void
192GroupManagerDB::deleteSchedule(const std::string& name)
193{
194 Sqlite3Statement statement(m_impl->m_database,
195 "DELETE FROM schedules WHERE schedule_name=?");
196 statement.bind(1, name, SQLITE_TRANSIENT);
197 statement.step();
198}
199
200void
201GroupManagerDB::renameSchedule(const std::string& oldName, const std::string& newName)
202{
203 BOOST_ASSERT(newName.length() != 0);
204
205 Sqlite3Statement statement(m_impl->m_database,
206 "UPDATE schedules SET schedule_name=? WHERE schedule_name=?");
207 statement.bind(1, newName, SQLITE_TRANSIENT);
208 statement.bind(2, oldName, SQLITE_TRANSIENT);
209 if (statement.step() != SQLITE_DONE)
210 BOOST_THROW_EXCEPTION(Error("Cannot rename the schedule from database"));
211}
212
213void
214GroupManagerDB::updateSchedule(const std::string& name, const Schedule& schedule)
215{
216 if (!hasSchedule(name)) {
217 addSchedule(name, schedule);
218 return;
219 }
220
221 Sqlite3Statement statement(m_impl->m_database,
222 "UPDATE schedules SET schedule=? WHERE schedule_name=?");
223 statement.bind(1, schedule.wireEncode(), SQLITE_TRANSIENT);
224 statement.bind(2, name, SQLITE_TRANSIENT);
225 statement.step();
226}
227
228bool
229GroupManagerDB::hasMember(const Name& identity) const
230{
231 Sqlite3Statement statement(m_impl->m_database,
232 "SELECT member_id FROM members WHERE member_name=?");
233 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
234 return (statement.step() == SQLITE_ROW);
235}
236
237std::list<Name>
238GroupManagerDB::listAllMembers() const
239{
240 std::list<Name> result;
241 Sqlite3Statement statement(m_impl->m_database,
242 "SELECT member_name FROM members");
243
244 result.clear();
245 while (statement.step() == SQLITE_ROW) {
246 result.push_back(Name(statement.getBlock(0)));
247 }
248 return result;
249}
250
251Data
252GroupManagerDB::getMemberCert(const Name& identity) const
253{
254 Sqlite3Statement statement(m_impl->m_database,
255 "SELECT member_cert FROM members WHERE member_name=?");
256 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
257 Data result;
258 if (statement.step() == SQLITE_ROW) {
259 result.wireDecode(statement.getBlock(0));
260 }
261 else {
262 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
263 }
264 return result;
265}
266
267std::string
268GroupManagerDB::getMemberSchedule(const Name& identity) const
269{
270 Sqlite3Statement statement(m_impl->m_database,
271 "SELECT schedule_name\
272 FROM schedules JOIN members\
273 ON schedules.schedule_id = members.schedule_id\
274 WHERE member_name=?");
275 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
276
277 std::string result = "";
278 if (statement.step() == SQLITE_ROW) {
279 result = statement.getString(0);
280 }
281 else {
282 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
283 }
284 return result;
285}
286
287void
288GroupManagerDB::addMember(const std::string& scheduleName, const Data& certificate)
289{
290 int scheduleId = m_impl->getScheduleId(scheduleName);
291 if (scheduleId == -1)
292 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
293
294 IdentityCertificate cert(certificate);
295 Name memberName = cert.getPublicKeyName().getPrefix(-1);
296
297 Sqlite3Statement statement(m_impl->m_database,
298 "INSERT INTO members(schedule_id, member_name, member_cert)\
299 values (?, ?, ?)");
300 statement.bind(1, scheduleId);
301 statement.bind(2, memberName.wireEncode(), SQLITE_TRANSIENT);
302 statement.bind(3, certificate.wireEncode(), SQLITE_TRANSIENT);
303 if (statement.step() != SQLITE_DONE)
304 BOOST_THROW_EXCEPTION(Error("Cannot add the member to database"));
305}
306
307void
308GroupManagerDB::updateMemberSchedule(const Name& identity, const std::string& scheduleName)
309{
310 int scheduleId = m_impl->getScheduleId(scheduleName);
311 if (scheduleId == -1)
312 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
313
314 Sqlite3Statement statement(m_impl->m_database,
315 "UPDATE members SET schedule_id=? WHERE member_name=?");
316 statement.bind(1, scheduleId);
317 statement.bind(2, identity.wireEncode(), SQLITE_TRANSIENT);
318 statement.step();
319}
320
321void
322GroupManagerDB::deleteMember(const Name& identity)
323{
324 Sqlite3Statement statement(m_impl->m_database,
325 "DELETE FROM members WHERE member_name=?");
326 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
327 statement.step();
328}
329
330} // namespace gep
331} // namespace ndn