diff --git a/netconf/SqliteNetworkConfigMaster.cpp b/netconf/SqliteNetworkConfigMaster.cpp index 48711c869..88d96c2a0 100644 --- a/netconf/SqliteNetworkConfigMaster.cpp +++ b/netconf/SqliteNetworkConfigMaster.cpp @@ -66,27 +66,36 @@ SqliteNetworkConfigMaster::SqliteNetworkConfigMaster(const Identity &signingId,c throw std::runtime_error("SqliteNetworkConfigMaster cannot open database file"); sqlite3_busy_timeout(_db,10000); - sqlite3_stmt *s = (sqlite3_stmt *)0; - if (sqlite3_prepare_v2(_db,"SELECT v FROM Config WHERE k = 'schemaVersion';",-1,&s,(const char **)0) != SQLITE_OK) { - sqlite3_close(_db); - throw std::runtime_error("SqliteNetworkConfigMaster cannot create prepared statement (library problem?)"); + sqlite3_stmt *s; + for(int k=0;k<2;++k) { + s = (sqlite3_stmt *)0; + if ((sqlite3_prepare_v2(_db,"SELECT 'v' FROM Config WHERE 'k' = 'schemaVersion';",-1,&s,(const char **)0) != SQLITE_OK)||(!s)) { + if (sqlite3_exec(_db,ZT_NETCONF_SCHEMA_SQL"INSERT INTO Config (k,v) VALUES ('schemaVersion',"ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR");",0,0,0) != SQLITE_OK) { + sqlite3_close(_db); + throw std::runtime_error("SqliteNetworkConfigMaster cannot initialize database and/or insert schemaVersion into Config table"); + } else { + // Initialized database and set schema version, so we are done. + return; + } + } else break; } if (!s) { sqlite3_close(_db); - throw std::runtime_error("SqliteNetworkConfigMaster cannot create prepared statement (library problem?)"); + throw std::runtime_error("SqliteNetworkConfigMaster unable to create prepared statement or initialize database"); } - int schemaVersion = -1; + // If we made it here, database was opened and prepared statement was created + // to check schema version. Check and upgrade if needed. + + int schemaVersion = -1234; if (sqlite3_step(s) == SQLITE_ROW) schemaVersion = sqlite3_column_int(s,0); sqlite3_finalize(s); - if (schemaVersion == -1) { - if (sqlite3_exec(_db,ZT_NETCONF_SCHEMA_SQL"INSERT INTO Config (k,v) VALUES ('schemaVersion',"ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR");",0,0,0) != SQLITE_OK) { - sqlite3_close(_db); - throw std::runtime_error("SqliteNetworkConfigMaster cannot initialize database and/or insert schemaVersion into Config table"); - } + if (schemaVersion == -1234) { + sqlite3_close(_db); + throw std::runtime_error("SqliteNetworkConfigMaster schemaVersion not found in Config table (init failure?)"); } else if (schemaVersion != ZT_NETCONF_SQLITE_SCHEMA_VERSION) { // Note -- this will eventually run auto-upgrades so this isn't how it'll work going forward sqlite3_close(_db); diff --git a/selftest.cpp b/selftest.cpp index f083018a8..e8f61d8d4 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -55,6 +55,10 @@ #include "node/Defaults.hpp" #include "node/Node.hpp" +#ifdef ZT_ENABLE_NETCONF_MASTER +#include "netconf/SqliteNetworkConfigMaster.hpp" +#endif // ZT_ENABLE_NETCONF_MASTER + #ifdef __WINDOWS__ #include #endif @@ -636,6 +640,27 @@ static int testOther() return 0; } +static int testSqliteNetconfMaster() +{ +#ifdef ZT_ENABLE_NETCONF_MASTER + try { + std::cout << "[netconf] Generating signing identity..." << std::endl; + Identity signingId; + signingId.generate(); + + std::cout << "[netconf] Creating database..." << std::endl; + SqliteNetworkConfigMaster netconf(signingId,"netconf-test.db"); + } catch (std::runtime_error &exc) { + std::cout << "FAIL! (unexpected exception: " << exc.what() << ")" << std::endl; + return -1; + } catch ( ... ) { + std::cout << "FAIL! (unexpected exception: ...)" << std::endl; + return -1; + } +#endif // ZT_ENABLE_NETCONF_MASTER + return 0; +} + #ifdef __WINDOWS__ int _tmain(int argc, _TCHAR* argv[]) #else @@ -686,6 +711,7 @@ int main(int argc,char **argv) srand((unsigned int)time(0)); + r |= testSqliteNetconfMaster(); r |= testCrypto(); r |= testHttp(); r |= testPacket();