Profiling.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include <sys/stat.h>
  2. #include <boost/property_tree/ptree.hpp>
  3. #include <boost/property_tree/ini_parser.hpp>
  4. #include "Base.h"
  5. #include "FS.h"
  6. #include "Log.h"
  7. #include "Profiling.h"
  8. namespace i2p
  9. {
  10. namespace data
  11. {
  12. i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
  13. RouterProfile::RouterProfile ():
  14. m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
  15. m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
  16. m_NumTimesTaken (0), m_NumTimesRejected (0)
  17. {
  18. }
  19. boost::posix_time::ptime RouterProfile::GetTime () const
  20. {
  21. return boost::posix_time::second_clock::local_time();
  22. }
  23. void RouterProfile::UpdateTime ()
  24. {
  25. m_LastUpdateTime = GetTime ();
  26. }
  27. void RouterProfile::Save (const IdentHash& identHash)
  28. {
  29. // fill sections
  30. boost::property_tree::ptree participation;
  31. participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
  32. participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
  33. participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
  34. boost::property_tree::ptree usage;
  35. usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
  36. usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
  37. // fill property tree
  38. boost::property_tree::ptree pt;
  39. pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
  40. pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
  41. pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
  42. // save to file
  43. std::string ident = identHash.ToBase64 ();
  44. std::string path = m_ProfilesStorage.Path(ident);
  45. try {
  46. boost::property_tree::write_ini (path, pt);
  47. } catch (std::exception& ex) {
  48. /* boost exception verbose enough */
  49. LogPrint (eLogError, "Profiling: ", ex.what ());
  50. }
  51. }
  52. void RouterProfile::Load (const IdentHash& identHash)
  53. {
  54. std::string ident = identHash.ToBase64 ();
  55. std::string path = m_ProfilesStorage.Path(ident);
  56. boost::property_tree::ptree pt;
  57. if (!i2p::fs::Exists(path))
  58. {
  59. LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
  60. return;
  61. }
  62. try
  63. {
  64. boost::property_tree::read_ini (path, pt);
  65. } catch (std::exception& ex)
  66. {
  67. /* boost exception verbose enough */
  68. LogPrint (eLogError, "Profiling: ", ex.what ());
  69. return;
  70. }
  71. try
  72. {
  73. auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
  74. if (t.length () > 0)
  75. m_LastUpdateTime = boost::posix_time::time_from_string (t);
  76. if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
  77. {
  78. try
  79. {
  80. // read participations
  81. auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
  82. m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
  83. m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
  84. m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
  85. }
  86. catch (boost::property_tree::ptree_bad_path& ex)
  87. {
  88. LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
  89. }
  90. try
  91. {
  92. // read usage
  93. auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
  94. m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
  95. m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
  96. }
  97. catch (boost::property_tree::ptree_bad_path& ex)
  98. {
  99. LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
  100. }
  101. }
  102. else
  103. *this = RouterProfile ();
  104. }
  105. catch (std::exception& ex)
  106. {
  107. LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
  108. }
  109. }
  110. void RouterProfile::TunnelBuildResponse (uint8_t ret)
  111. {
  112. UpdateTime ();
  113. if (ret > 0)
  114. m_NumTunnelsDeclined++;
  115. else
  116. m_NumTunnelsAgreed++;
  117. }
  118. void RouterProfile::TunnelNonReplied ()
  119. {
  120. m_NumTunnelsNonReplied++;
  121. UpdateTime ();
  122. }
  123. bool RouterProfile::IsLowPartcipationRate () const
  124. {
  125. return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
  126. }
  127. bool RouterProfile::IsLowReplyRate () const
  128. {
  129. auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
  130. return m_NumTunnelsNonReplied > 10*(total + 1);
  131. }
  132. bool RouterProfile::IsBad ()
  133. {
  134. auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
  135. if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
  136. {
  137. // reset profile
  138. m_NumTunnelsAgreed = 0;
  139. m_NumTunnelsDeclined = 0;
  140. m_NumTunnelsNonReplied = 0;
  141. isBad = false;
  142. }
  143. if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
  144. return isBad;
  145. }
  146. std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
  147. {
  148. auto profile = std::make_shared<RouterProfile> ();
  149. profile->Load (identHash); // if possible
  150. return profile;
  151. }
  152. void InitProfilesStorage ()
  153. {
  154. m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
  155. m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
  156. }
  157. void DeleteObsoleteProfiles ()
  158. {
  159. struct stat st;
  160. std::time_t now = std::time(nullptr);
  161. std::vector<std::string> files;
  162. m_ProfilesStorage.Traverse(files);
  163. for (const auto& path: files) {
  164. if (stat(path.c_str(), &st) != 0) {
  165. LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
  166. continue;
  167. }
  168. if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
  169. LogPrint(eLogDebug, "Profiling: removing expired peer profile: ", path);
  170. i2p::fs::Remove(path);
  171. }
  172. }
  173. }
  174. }
  175. }