diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-04-18 17:37:44 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-04-18 17:37:44 -0700 |
commit | bc61357a44cf4906dda2b30c4474ae891982e620 (patch) | |
tree | 284d70f7c20b1d057f3d52c9f437b6d9312b7a37 /controller | |
parent | f6d92eb737507e6c56cf59aa7b4c4fce679e23cd (diff) | |
download | infinitytier-bc61357a44cf4906dda2b30c4474ae891982e620.tar.gz infinitytier-bc61357a44cf4906dda2b30c4474ae891982e620.zip |
HTTP backend support for JSONDB
Diffstat (limited to 'controller')
-rw-r--r-- | controller/EmbeddedNetworkController.cpp | 2 | ||||
-rw-r--r-- | controller/JSONDB.cpp | 161 | ||||
-rw-r--r-- | controller/JSONDB.hpp | 12 |
3 files changed, 119 insertions, 56 deletions
diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 0884deda..597bc9c9 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -434,8 +434,6 @@ EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPa _db(dbPath), _node(node) { - OSUtils::mkdir(dbPath); - OSUtils::lockDownFile(dbPath,true); // networks might contain auth tokens, etc., so restrict directory permissions } EmbeddedNetworkController::~EmbeddedNetworkController() diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index 756664eb..afc0631d 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -18,43 +18,67 @@ #include "JSONDB.hpp" +#define ZT_JSONDB_HTTP_TIMEOUT 60000 + namespace ZeroTier { static const nlohmann::json _EMPTY_JSON(nlohmann::json::object()); +static const std::map<std::string,std::string> _ZT_JSONDB_GET_HEADERS; + +JSONDB::JSONDB(const std::string &basePath) : + _basePath(basePath) +{ + if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) { + // TODO: this doesn't yet support IPv6 since bracketed address notiation isn't supported. + // Typically it's used with 127.0.0.1 anyway. + std::string hn = _basePath.substr(7); + std::size_t hnend = hn.find_first_of('/'); + if (hnend != std::string::npos) + hn = hn.substr(0,hnend); + std::size_t hnsep = hn.find_last_of(':'); + if (hnsep != std::string::npos) + hn[hnsep] = '/'; + _httpAddr.fromString(hn); + if (hnend != std::string::npos) + _basePath = _basePath.substr(7 + hnend); + if (_basePath.length() == 0) + _basePath = "/"; + if (_basePath[0] != '/') + _basePath = std::string("/") + _basePath; + } else { + OSUtils::mkdir(_basePath.c_str()); + OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions + } + _reload(_basePath,std::string()); +} bool JSONDB::writeRaw(const std::string &n,const std::string &obj) { if (!_isValidObjectName(n)) return false; - - const std::string path(_genPath(n,true)); - if (!path.length()) - return false; - - const std::string buf(obj); - if (!OSUtils::writeFile(path.c_str(),buf)) - return false; - - return true; + if (_httpAddr) { + std::map<std::string,std::string> headers; + std::string body; + std::map<std::string,std::string> reqHeaders; + char tmp[64]; + Utils::snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)obj.length()); + reqHeaders["Content-Length"] = tmp; + reqHeaders["Content-Type"] = "application/json"; + const unsigned int sc = Http::PUT(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),reqHeaders,obj.data(),obj.length(),headers,body); + return (sc == 200); + } else { + const std::string path(_genPath(n,true)); + if (!path.length()) + return false; + return OSUtils::writeFile(path.c_str(),obj); + } } bool JSONDB::put(const std::string &n,const nlohmann::json &obj) { - if (!_isValidObjectName(n)) - return false; - - const std::string path(_genPath(n,true)); - if (!path.length()) - return false; - - const std::string buf(OSUtils::jsonDump(obj)); - if (!OSUtils::writeFile(path.c_str(),buf)) - return false; - - _E &e = _db[n]; - e.obj = obj; - - return true; + const bool r = writeRaw(n,OSUtils::jsonDump(obj)); + _db[n].obj = obj; + return r; } const nlohmann::json &JSONDB::get(const std::string &n) @@ -66,22 +90,28 @@ const nlohmann::json &JSONDB::get(const std::string &n) if (e != _db.end()) return e->second.obj; - const std::string path(_genPath(n,false)); - if (!path.length()) - return _EMPTY_JSON; std::string buf; - if (!OSUtils::readFile(path.c_str(),buf)) - return _EMPTY_JSON; + if (_httpAddr) { + std::map<std::string,std::string> headers; + const unsigned int sc = Http::GET(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,buf); + if (sc != 200) + return _EMPTY_JSON; + } else { + const std::string path(_genPath(n,false)); + if (!path.length()) + return _EMPTY_JSON; + if (!OSUtils::readFile(path.c_str(),buf)) + return _EMPTY_JSON; + } - _E &e2 = _db[n]; try { + _E &e2 = _db[n]; e2.obj = OSUtils::jsonParse(buf); + return e2.obj; } catch ( ... ) { - e2.obj = _EMPTY_JSON; - buf = "{}"; + _db.erase(n); + return _EMPTY_JSON; } - - return e2.obj; } void JSONDB::erase(const std::string &n) @@ -89,23 +119,50 @@ void JSONDB::erase(const std::string &n) if (!_isValidObjectName(n)) return; - std::string path(_genPath(n,true)); - if (!path.length()) - return; + if (_httpAddr) { + std::string body; + std::map<std::string,std::string> headers; + Http::DEL(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); + } else { + std::string path(_genPath(n,true)); + if (!path.length()) + return; + OSUtils::rm(path.c_str()); + } - OSUtils::rm(path.c_str()); _db.erase(n); } void JSONDB::_reload(const std::string &p,const std::string &b) { - std::vector<std::string> dl(OSUtils::listDirectory(p.c_str(),true)); - for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) { - printf("%s\n",di->c_str()); - if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) { - this->get(b + di->substr(0,di->length() - 5)); - } else { - this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR)); + if (_httpAddr) { + std::string body; + std::map<std::string,std::string> headers; + const unsigned int sc = Http::GET(2147483647,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),_basePath.c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); + if (sc == 200) { + try { + nlohmann::json dbImg(OSUtils::jsonParse(body)); + std::string tmp; + if (dbImg.is_object()) { + for(nlohmann::json::iterator i(dbImg.begin());i!=dbImg.end();++i) { + if (i.value().is_object()) { + tmp = i.key(); + _db[tmp].obj = i.value(); + } + } + } + } catch ( ... ) { + // TODO: report error? + } + } + } else { + std::vector<std::string> dl(OSUtils::listDirectory(p.c_str(),true)); + for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) { + if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) { + this->get(b + di->substr(0,di->length() - 5)); + } else { + this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR)); + } } } } @@ -130,15 +187,23 @@ std::string JSONDB::_genPath(const std::string &n,bool create) if (pt.size() == 0) return std::string(); + char sep; + if (_httpAddr) { + sep = '/'; + create = false; + } else { + sep = ZT_PATH_SEPARATOR; + } + std::string p(_basePath); if (create) OSUtils::mkdir(p.c_str()); for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i<j;++i) { - p.push_back(ZT_PATH_SEPARATOR); + p.push_back(sep); p.append(pt[i]); if (create) OSUtils::mkdir(p.c_str()); } - p.push_back(ZT_PATH_SEPARATOR); + p.push_back(sep); p.append(pt[pt.size()-1]); p.append(".json"); diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 00eeb8d8..c19112ed 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -31,22 +31,21 @@ #include "../node/Constants.hpp" #include "../node/Utils.hpp" +#include "../node/InetAddress.hpp" +#include "../node/Mutex.hpp" #include "../ext/json/json.hpp" #include "../osdep/OSUtils.hpp" +#include "../osdep/Http.hpp" namespace ZeroTier { /** - * Hierarchical JSON store that persists into the filesystem + * Hierarchical JSON store that persists into the filesystem or via HTTP */ class JSONDB { public: - JSONDB(const std::string &basePath) : - _basePath(basePath) - { - _reload(_basePath,std::string()); - } + JSONDB(const std::string &basePath); inline void reload() { @@ -106,6 +105,7 @@ private: inline bool operator!=(const _E &e) const { return (obj != e.obj); } }; + InetAddress _httpAddr; std::string _basePath; std::map<std::string,_E> _db; }; |