FileDB.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* (c) ZeroTier, Inc.
  2. * See LICENSE.txt in nonfree/
  3. */
  4. #include "FileDB.hpp"
  5. #include "../../node/Metrics.hpp"
  6. #include "opentelemetry/trace/provider.h"
  7. namespace ZeroTier {
  8. FileDB::FileDB(const char* path)
  9. : DB()
  10. , _path(path)
  11. , _networksPath(_path + ZT_PATH_SEPARATOR_S + "network")
  12. , _tracePath(_path + ZT_PATH_SEPARATOR_S + "trace")
  13. , _running(true)
  14. {
  15. auto provider = opentelemetry::trace::Provider::GetTracerProvider();
  16. auto tracer = provider->GetTracer("filedb");
  17. auto span = tracer->StartSpan("filedb::FileDB");
  18. auto scope = tracer->WithActiveSpan(span);
  19. OSUtils::mkdir(_path.c_str());
  20. OSUtils::lockDownFile(_path.c_str(), true);
  21. OSUtils::mkdir(_networksPath.c_str());
  22. OSUtils::mkdir(_tracePath.c_str());
  23. std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(), false));
  24. std::string buf;
  25. for (auto n = networks.begin(); n != networks.end(); ++n) {
  26. buf.clear();
  27. if ((n->length() == 21) && (OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(), buf))) {
  28. try {
  29. nlohmann::json network(OSUtils::jsonParse(buf));
  30. const std::string nwids = network["id"];
  31. if (nwids.length() == 16) {
  32. nlohmann::json nullJson;
  33. _networkChanged(nullJson, network, false);
  34. Metrics::network_count++;
  35. std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
  36. std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(), false));
  37. for (auto m = members.begin(); m != members.end(); ++m) {
  38. buf.clear();
  39. if ((m->length() == 15)
  40. && (OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(), buf))) {
  41. try {
  42. nlohmann::json member(OSUtils::jsonParse(buf));
  43. const std::string addrs = member["id"];
  44. if (addrs.length() == 10) {
  45. nlohmann::json nullJson2;
  46. _memberChanged(nullJson2, member, false);
  47. Metrics::member_count++;
  48. }
  49. }
  50. catch (...) {
  51. }
  52. }
  53. }
  54. }
  55. }
  56. catch (...) {
  57. }
  58. }
  59. }
  60. }
  61. FileDB::~FileDB()
  62. {
  63. try {
  64. _online_l.lock();
  65. _running = false;
  66. _online_l.unlock();
  67. _onlineUpdateThread.join();
  68. }
  69. catch (...) {
  70. }
  71. }
  72. bool FileDB::waitForReady()
  73. {
  74. return true;
  75. }
  76. bool FileDB::isReady()
  77. {
  78. return true;
  79. }
  80. bool FileDB::save(nlohmann::json& record, bool notifyListeners)
  81. {
  82. auto provider = opentelemetry::trace::Provider::GetTracerProvider();
  83. auto tracer = provider->GetTracer("filedb");
  84. auto span = tracer->StartSpan("filedb::save");
  85. auto scope = tracer->WithActiveSpan(span);
  86. char p1[4096], p2[4096], pb[4096];
  87. bool modified = false;
  88. try {
  89. const std::string objtype = record["objtype"];
  90. if (objtype == "network") {
  91. auto span = tracer->StartSpan("filedb::save::network");
  92. auto scope = tracer->WithActiveSpan(span);
  93. const uint64_t nwid = OSUtils::jsonIntHex(record["id"], 0ULL);
  94. if (nwid) {
  95. nlohmann::json old;
  96. get(nwid, old);
  97. if ((! old.is_object()) || (! _compareRecords(old, record))) {
  98. record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
  99. OSUtils::ztsnprintf(
  100. p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), nwid);
  101. if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
  102. fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
  103. }
  104. _networkChanged(old, record, notifyListeners);
  105. modified = true;
  106. }
  107. }
  108. }
  109. else if (objtype == "member") {
  110. auto span = tracer->StartSpan("filedb::save::member");
  111. auto scope = tracer->WithActiveSpan(span);
  112. const uint64_t id = OSUtils::jsonIntHex(record["id"], 0ULL);
  113. const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"], 0ULL);
  114. if ((id) && (nwid)) {
  115. nlohmann::json network, old;
  116. get(nwid, network, id, old);
  117. if ((! old.is_object()) || (! _compareRecords(old, record))) {
  118. record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
  119. OSUtils::ztsnprintf(
  120. pb, sizeof(pb), "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",
  121. _networksPath.c_str(), (unsigned long long)nwid);
  122. OSUtils::ztsnprintf(
  123. p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.10llx.json", pb, (unsigned long long)id);
  124. if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
  125. OSUtils::ztsnprintf(
  126. p2, sizeof(p2), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(),
  127. (unsigned long long)nwid);
  128. OSUtils::mkdir(p2);
  129. OSUtils::mkdir(pb);
  130. if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
  131. fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
  132. }
  133. }
  134. _memberChanged(old, record, notifyListeners);
  135. modified = true;
  136. }
  137. }
  138. }
  139. }
  140. catch (...) {
  141. } // drop invalid records missing fields
  142. return modified;
  143. }
  144. void FileDB::eraseNetwork(const uint64_t networkId)
  145. {
  146. auto provider = opentelemetry::trace::Provider::GetTracerProvider();
  147. auto tracer = provider->GetTracer("filedb");
  148. auto span = tracer->StartSpan("filedb::eraseNetwork");
  149. auto scope = tracer->WithActiveSpan(span);
  150. nlohmann::json network, nullJson;
  151. get(networkId, network);
  152. char p[16384];
  153. OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), networkId);
  154. OSUtils::rm(p);
  155. OSUtils::ztsnprintf(
  156. p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(), (unsigned long long)networkId);
  157. OSUtils::rmDashRf(p);
  158. _networkChanged(network, nullJson, true);
  159. std::lock_guard<std::mutex> l(this->_online_l);
  160. this->_online.erase(networkId);
  161. }
  162. void FileDB::eraseMember(const uint64_t networkId, const uint64_t memberId)
  163. {
  164. auto provider = opentelemetry::trace::Provider::GetTracerProvider();
  165. auto tracer = provider->GetTracer("filedb");
  166. auto span = tracer->StartSpan("filedb::eraseMember");
  167. auto scope = tracer->WithActiveSpan(span);
  168. nlohmann::json network, member, nullJson;
  169. get(networkId, network, memberId, member);
  170. char p[4096];
  171. OSUtils::ztsnprintf(
  172. p, sizeof(p),
  173. "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",
  174. _networksPath.c_str(), networkId, memberId);
  175. OSUtils::rm(p);
  176. _memberChanged(member, nullJson, true);
  177. std::lock_guard<std::mutex> l(this->_online_l);
  178. this->_online[networkId].erase(memberId);
  179. }
  180. void FileDB::nodeIsOnline(
  181. const uint64_t networkId,
  182. const uint64_t memberId,
  183. const InetAddress& physicalAddress,
  184. const char* osArch)
  185. {
  186. auto provider = opentelemetry::trace::Provider::GetTracerProvider();
  187. auto tracer = provider->GetTracer("filedb");
  188. auto span = tracer->StartSpan("filedb::nodeIsOnline");
  189. auto scope = tracer->WithActiveSpan(span);
  190. char mid[32], atmp[64];
  191. OSUtils::ztsnprintf(mid, sizeof(mid), "%.10llx", (unsigned long long)memberId);
  192. physicalAddress.toString(atmp);
  193. std::lock_guard<std::mutex> l(this->_online_l);
  194. this->_online[networkId][memberId][OSUtils::now()] = physicalAddress;
  195. }
  196. void FileDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
  197. {
  198. this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
  199. }
  200. } // namespace ZeroTier