mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Clean up and restructure sources
This commit is contained in:
151
src/ripple/basics/impl/CheckLibraryVersions.cpp
Normal file
151
src/ripple/basics/impl/CheckLibraryVersions.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <beast/module/core/diagnostic/SemanticVersion.h>
|
||||
#include <boost/version.hpp>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include <ripple/basics/CheckLibraryVersions.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace version {
|
||||
|
||||
/** Both Boost and OpenSSL have integral version numbers. */
|
||||
typedef unsigned long long VersionNumber;
|
||||
|
||||
/** Minimal required boost version. */
|
||||
static const char boostMinimal[] = "1.55.0";
|
||||
|
||||
/** Minimal required OpenSSL version. */
|
||||
static const char openSSLMinimal[] = "1.0.1-g";
|
||||
|
||||
std::string boostVersion(VersionNumber boostVersion = BOOST_VERSION)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (boostVersion / 100000) << "."
|
||||
<< (boostVersion / 100 % 1000) << "."
|
||||
<< (boostVersion % 100);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string openSSLVersion(VersionNumber openSSLVersion = OPENSSL_VERSION_NUMBER)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (openSSLVersion / 0x10000000L) << "."
|
||||
<< (openSSLVersion / 0x100000 % 0x100) << "."
|
||||
<< (openSSLVersion / 0x1000 % 0x100);
|
||||
auto patchNo = openSSLVersion % 0x10;
|
||||
if (patchNo)
|
||||
ss << '-' << char('a' + patchNo - 1);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void checkVersion(std::string name, std::string required, std::string actual)
|
||||
{
|
||||
beast::SemanticVersion r, a;
|
||||
if (!r.parse(required)) {
|
||||
throw std::runtime_error("Didn't understand required version of " +
|
||||
name + ": " + required);
|
||||
}
|
||||
if (!a.parse(actual)) {
|
||||
throw std::runtime_error("Didn't understand actual version of " +
|
||||
name + ": " + required);
|
||||
}
|
||||
|
||||
if (a < r) {
|
||||
throw std::runtime_error("Your " + name + " library is out of date.\n" +
|
||||
"Your version: " + actual + "\n" +
|
||||
"Required version: " + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void checkBoost(std::string version = boostVersion())
|
||||
{
|
||||
checkVersion("Boost", boostMinimal, version);
|
||||
}
|
||||
|
||||
void checkOpenSSL(std::string version = openSSLVersion())
|
||||
{
|
||||
checkVersion("OpenSSL", openSSLMinimal, version);
|
||||
}
|
||||
|
||||
void checkLibraryVersions()
|
||||
{
|
||||
checkBoost();
|
||||
checkOpenSSL();
|
||||
}
|
||||
|
||||
struct CheckLibraryVersions_test : beast::unit_test::suite
|
||||
{
|
||||
void print_message()
|
||||
{
|
||||
log << "ssl minimal: " << openSSLMinimal << "\n"
|
||||
<< "ssl actual: " << openSSLVersion() << "\n"
|
||||
<< "boost minimal: " << boostMinimal << "\n"
|
||||
<< "boost actual: " << boostVersion() << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
|
||||
void test_bad_ssl()
|
||||
{
|
||||
std::string error;
|
||||
try {
|
||||
checkOpenSSL(openSSLVersion(0x0090819fL));
|
||||
} catch (std::runtime_error& e) {
|
||||
error = e.what();
|
||||
}
|
||||
auto expectedError = "Your OpenSSL library is out of date.\n"
|
||||
"Your version: 0.9.8-o\n"
|
||||
"Required version: ";
|
||||
unexpected(error.find(expectedError) != 0, error);
|
||||
}
|
||||
|
||||
void test_bad_boost()
|
||||
{
|
||||
std::string error;
|
||||
try {
|
||||
checkBoost(boostVersion(105400));
|
||||
} catch (std::runtime_error& e) {
|
||||
error = e.what();
|
||||
}
|
||||
auto expectedError = "Your Boost library is out of date.\n"
|
||||
"Your version: 1.54.0\n"
|
||||
"Required version: ";
|
||||
unexpected(error.find(expectedError) != 0, error);
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
print_message();
|
||||
checkLibraryVersions();
|
||||
|
||||
test_bad_ssl();
|
||||
test_bad_boost();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(CheckLibraryVersions, ripple_basics, ripple);
|
||||
|
||||
} // namespace version
|
||||
} // namespace ripple
|
||||
98
src/ripple/basics/impl/CountedObject.cpp
Normal file
98
src/ripple/basics/impl/CountedObject.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
CountedObjects& CountedObjects::getInstance ()
|
||||
{
|
||||
static CountedObjects instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
CountedObjects::CountedObjects ()
|
||||
: m_count (0)
|
||||
, m_head (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CountedObjects::~CountedObjects ()
|
||||
{
|
||||
}
|
||||
|
||||
CountedObjects::List CountedObjects::getCounts (int minimumThreshold) const
|
||||
{
|
||||
List counts;
|
||||
|
||||
// When other operations are concurrent, the count
|
||||
// might be temporarily less than the actual count.
|
||||
int const count = m_count.load ();
|
||||
|
||||
counts.reserve (count);
|
||||
|
||||
CounterBase* counter = m_head.load ();
|
||||
|
||||
while (counter != nullptr)
|
||||
{
|
||||
if (counter->getCount () >= minimumThreshold)
|
||||
{
|
||||
Entry entry;
|
||||
|
||||
entry.first = counter->getName ();
|
||||
entry.second = counter->getCount ();
|
||||
|
||||
counts.push_back (entry);
|
||||
}
|
||||
|
||||
counter = counter->getNext ();
|
||||
}
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CountedObjects::CounterBase::CounterBase ()
|
||||
: m_count (0)
|
||||
{
|
||||
// Insert ourselves at the front of the lock-free linked list
|
||||
|
||||
CountedObjects& instance = CountedObjects::getInstance ();
|
||||
CounterBase* head;
|
||||
|
||||
do
|
||||
{
|
||||
head = instance.m_head.load ();
|
||||
m_next = head;
|
||||
}
|
||||
while (instance.m_head.exchange (this) != head);
|
||||
|
||||
++instance.m_count;
|
||||
}
|
||||
|
||||
CountedObjects::CounterBase::~CounterBase ()
|
||||
{
|
||||
// VFALCO NOTE If the counters are destroyed before the singleton,
|
||||
// undefined behavior will result if the singleton's member
|
||||
// functions are called.
|
||||
}
|
||||
|
||||
} // ripple
|
||||
328
src/ripple/basics/impl/Log.cpp
Normal file
328
src/ripple/basics/impl/Log.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
// VFALCO TODO Use std::chrono
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Logs::Sink::Sink (std::string const& partition,
|
||||
beast::Journal::Severity severity, Logs& logs)
|
||||
: logs_(logs)
|
||||
, partition_(partition)
|
||||
{
|
||||
beast::Journal::Sink::severity (severity);
|
||||
}
|
||||
|
||||
void
|
||||
Logs::Sink::write (beast::Journal::Severity level, std::string const& text)
|
||||
{
|
||||
logs_.write (level, partition_, text, console());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Logs::File::File()
|
||||
: m_stream (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Logs::File::~File()
|
||||
{
|
||||
}
|
||||
|
||||
bool Logs::File::isOpen () const noexcept
|
||||
{
|
||||
return m_stream != nullptr;
|
||||
}
|
||||
|
||||
bool Logs::File::open (boost::filesystem::path const& path)
|
||||
{
|
||||
close ();
|
||||
|
||||
bool wasOpened = false;
|
||||
|
||||
// VFALCO TODO Make this work with Unicode file paths
|
||||
std::unique_ptr <std::ofstream> stream (
|
||||
new std::ofstream (path.c_str (), std::fstream::app));
|
||||
|
||||
if (stream->good ())
|
||||
{
|
||||
m_path = path;
|
||||
|
||||
m_stream = std::move (stream);
|
||||
|
||||
wasOpened = true;
|
||||
}
|
||||
|
||||
return wasOpened;
|
||||
}
|
||||
|
||||
bool Logs::File::closeAndReopen ()
|
||||
{
|
||||
close ();
|
||||
|
||||
return open (m_path);
|
||||
}
|
||||
|
||||
void Logs::File::close ()
|
||||
{
|
||||
m_stream = nullptr;
|
||||
}
|
||||
|
||||
void Logs::File::write (char const* text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
(*m_stream) << text;
|
||||
}
|
||||
|
||||
void Logs::File::writeln (char const* text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
{
|
||||
(*m_stream) << text;
|
||||
(*m_stream) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Logs::Logs()
|
||||
: level_ (beast::Journal::kWarning) // default severity
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Logs::open (boost::filesystem::path const& pathToLogFile)
|
||||
{
|
||||
return file_.open(pathToLogFile);
|
||||
}
|
||||
|
||||
Logs::Sink&
|
||||
Logs::get (std::string const& name)
|
||||
{
|
||||
std::lock_guard <std::mutex> lock (mutex_);
|
||||
auto const result (sinks_.emplace (std::piecewise_construct,
|
||||
std::forward_as_tuple(name), std::forward_as_tuple (name,
|
||||
level_, *this)));
|
||||
return result.first->second;
|
||||
}
|
||||
|
||||
Logs::Sink&
|
||||
Logs::operator[] (std::string const& name)
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
|
||||
beast::Journal
|
||||
Logs::journal (std::string const& name)
|
||||
{
|
||||
return beast::Journal (get(name));
|
||||
}
|
||||
|
||||
beast::Journal::Severity
|
||||
Logs::severity() const
|
||||
{
|
||||
return level_;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::severity (beast::Journal::Severity level)
|
||||
{
|
||||
std::lock_guard <std::mutex> lock (mutex_);
|
||||
level_ = level;
|
||||
for (auto& sink : sinks_)
|
||||
sink.second.severity (level);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
Logs::partition_severities() const
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> list;
|
||||
std::lock_guard <std::mutex> lock (mutex_);
|
||||
list.reserve (sinks_.size());
|
||||
for (auto const& e : sinks_)
|
||||
list.push_back(std::make_pair(e.first,
|
||||
toString(fromSeverity(e.second.severity()))));
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::write (beast::Journal::Severity level, std::string const& partition,
|
||||
std::string const& text, bool console)
|
||||
{
|
||||
std::string s;
|
||||
format (s, text, level, partition);
|
||||
std::lock_guard <std::mutex> lock (mutex_);
|
||||
file_.writeln (s);
|
||||
std::cerr << s << '\n';
|
||||
// VFALCO TODO Fix console output
|
||||
//if (console)
|
||||
// out_.write_console(s);
|
||||
}
|
||||
|
||||
std::string
|
||||
Logs::rotate()
|
||||
{
|
||||
std::lock_guard <std::mutex> lock (mutex_);
|
||||
bool const wasOpened = file_.closeAndReopen ();
|
||||
if (wasOpened)
|
||||
return "The log file was closed and reopened.";
|
||||
return "The log file could not be closed and reopened.";
|
||||
}
|
||||
|
||||
LogSeverity
|
||||
Logs::fromSeverity (beast::Journal::Severity level)
|
||||
{
|
||||
using beast::Journal;
|
||||
switch (level)
|
||||
{
|
||||
case Journal::kTrace: return lsTRACE;
|
||||
case Journal::kDebug: return lsDEBUG;
|
||||
case Journal::kInfo: return lsINFO;
|
||||
case Journal::kWarning: return lsWARNING;
|
||||
case Journal::kError: return lsERROR;
|
||||
|
||||
default:
|
||||
bassertfalse;
|
||||
case Journal::kFatal:
|
||||
break;
|
||||
}
|
||||
|
||||
return lsFATAL;
|
||||
}
|
||||
|
||||
beast::Journal::Severity
|
||||
Logs::toSeverity (LogSeverity level)
|
||||
{
|
||||
using beast::Journal;
|
||||
switch (level)
|
||||
{
|
||||
case lsTRACE: return Journal::kTrace;
|
||||
case lsDEBUG: return Journal::kDebug;
|
||||
case lsINFO: return Journal::kInfo;
|
||||
case lsWARNING: return Journal::kWarning;
|
||||
case lsERROR: return Journal::kError;
|
||||
default:
|
||||
bassertfalse;
|
||||
case lsFATAL:
|
||||
break;
|
||||
}
|
||||
|
||||
return Journal::kFatal;
|
||||
}
|
||||
|
||||
std::string
|
||||
Logs::toString (LogSeverity s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case lsTRACE: return "Trace";
|
||||
case lsDEBUG: return "Debug";
|
||||
case lsINFO: return "Info";
|
||||
case lsWARNING: return "Warning";
|
||||
case lsERROR: return "Error";
|
||||
case lsFATAL: return "Fatal";
|
||||
default:
|
||||
assert (false);
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
LogSeverity
|
||||
Logs::fromString (std::string const& s)
|
||||
{
|
||||
if (boost::iequals (s, "trace"))
|
||||
return lsTRACE;
|
||||
|
||||
if (boost::iequals (s, "debug"))
|
||||
return lsDEBUG;
|
||||
|
||||
if (boost::iequals (s, "info") || boost::iequals (s, "information"))
|
||||
return lsINFO;
|
||||
|
||||
if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings"))
|
||||
return lsWARNING;
|
||||
|
||||
if (boost::iequals (s, "error") || boost::iequals (s, "errors"))
|
||||
return lsERROR;
|
||||
|
||||
if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals"))
|
||||
return lsFATAL;
|
||||
|
||||
return lsINVALID;
|
||||
}
|
||||
|
||||
// Replace the first secret, if any, with asterisks
|
||||
std::string
|
||||
Logs::scrub (std::string s)
|
||||
{
|
||||
using namespace std;
|
||||
char const* secretToken = "\"secret\"";
|
||||
// Look for the first occurrence of "secret" in the string.
|
||||
size_t startingPosition = s.find (secretToken);
|
||||
if (startingPosition != string::npos)
|
||||
{
|
||||
// Found it, advance past the token.
|
||||
startingPosition += strlen (secretToken);
|
||||
// Replace the next 35 characters at most, without overwriting the end.
|
||||
size_t endingPosition = std::min (startingPosition + 35, s.size () - 1);
|
||||
for (size_t i = startingPosition; i < endingPosition; ++i)
|
||||
s [i] = '*';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::format (std::string& output, std::string const& message,
|
||||
beast::Journal::Severity severity, std::string const& partition)
|
||||
{
|
||||
output.reserve (message.size() + partition.size() + 100);
|
||||
|
||||
output = boost::posix_time::to_simple_string (
|
||||
boost::posix_time::second_clock::universal_time ());
|
||||
|
||||
output += " ";
|
||||
if (! partition.empty ())
|
||||
output += partition + ":";
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case beast::Journal::kTrace: output += "TRC "; break;
|
||||
case beast::Journal::kDebug: output += "DBG "; break;
|
||||
case beast::Journal::kInfo: output += "NFO "; break;
|
||||
case beast::Journal::kWarning: output += "WRN "; break;
|
||||
case beast::Journal::kError: output += "ERR "; break;
|
||||
default:
|
||||
bassertfalse;
|
||||
case beast::Journal::kFatal: output += "FTL "; break;
|
||||
}
|
||||
|
||||
output += scrub (message);
|
||||
|
||||
if (output.size() > maximumMessageCharacters)
|
||||
{
|
||||
output.resize (maximumMessageCharacters - 3);
|
||||
output += "...";
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
335
src/ripple/basics/impl/RangeSet.cpp
Normal file
335
src/ripple/basics/impl/RangeSet.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO NOTE std::min and std::max not good enough?
|
||||
// NOTE Why isn't this written as a template?
|
||||
// TODO Replace this with std calls.
|
||||
//
|
||||
inline std::uint32_t min (std::uint32_t x, std::uint32_t y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
inline std::uint32_t max (std::uint32_t x, std::uint32_t y)
|
||||
{
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
|
||||
bool RangeSet::hasValue (std::uint32_t v) const
|
||||
{
|
||||
BOOST_FOREACH (const value_type & it, mRanges)
|
||||
{
|
||||
if (contains (it, v))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::uint32_t RangeSet::getFirst () const
|
||||
{
|
||||
const_iterator it = mRanges.begin ();
|
||||
|
||||
if (it == mRanges.end ())
|
||||
return absent;
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
std::uint32_t RangeSet::getNext (std::uint32_t v) const
|
||||
{
|
||||
BOOST_FOREACH (const value_type & it, mRanges)
|
||||
{
|
||||
if (it.first > v)
|
||||
return it.first;
|
||||
|
||||
if (contains (it, v + 1))
|
||||
return v + 1;
|
||||
}
|
||||
return absent;
|
||||
}
|
||||
|
||||
std::uint32_t RangeSet::getLast () const
|
||||
{
|
||||
const_reverse_iterator it = mRanges.rbegin ();
|
||||
|
||||
if (it == mRanges.rend ())
|
||||
return absent;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::uint32_t RangeSet::getPrev (std::uint32_t v) const
|
||||
{
|
||||
BOOST_REVERSE_FOREACH (const value_type & it, mRanges)
|
||||
{
|
||||
if (it.second < v)
|
||||
return it.second;
|
||||
|
||||
if (contains (it, v + 1))
|
||||
return v - 1;
|
||||
}
|
||||
return absent;
|
||||
}
|
||||
|
||||
// Return the largest number not in the set that is less than the given number
|
||||
//
|
||||
std::uint32_t RangeSet::prevMissing (std::uint32_t v) const
|
||||
{
|
||||
std::uint32_t result = absent;
|
||||
|
||||
if (v != 0)
|
||||
{
|
||||
checkInternalConsistency ();
|
||||
|
||||
// Handle the case where the loop reaches the terminating condition
|
||||
//
|
||||
result = v - 1;
|
||||
|
||||
for (const_reverse_iterator cur = mRanges.rbegin (); cur != mRanges.rend (); ++cur)
|
||||
{
|
||||
// See if v-1 is in the range
|
||||
if (contains (*cur, result))
|
||||
{
|
||||
result = cur->first - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bassert (result == absent || !hasValue (result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RangeSet::setValue (std::uint32_t v)
|
||||
{
|
||||
if (!hasValue (v))
|
||||
{
|
||||
mRanges[v] = v;
|
||||
|
||||
simplify ();
|
||||
}
|
||||
}
|
||||
|
||||
void RangeSet::setRange (std::uint32_t minV, std::uint32_t maxV)
|
||||
{
|
||||
while (hasValue (minV))
|
||||
{
|
||||
++minV;
|
||||
|
||||
if (minV >= maxV)
|
||||
return;
|
||||
}
|
||||
|
||||
mRanges[minV] = maxV;
|
||||
|
||||
simplify ();
|
||||
}
|
||||
|
||||
void RangeSet::clearValue (std::uint32_t v)
|
||||
{
|
||||
for (iterator it = mRanges.begin (); it != mRanges.end (); ++it)
|
||||
{
|
||||
if (contains (*it, v))
|
||||
{
|
||||
if (it->first == v)
|
||||
{
|
||||
if (it->second == v)
|
||||
{
|
||||
mRanges.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint32_t oldEnd = it->second;
|
||||
mRanges.erase(it);
|
||||
mRanges[v + 1] = oldEnd;
|
||||
}
|
||||
}
|
||||
else if (it->second == v)
|
||||
{
|
||||
-- (it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint32_t oldEnd = it->second;
|
||||
it->second = v - 1;
|
||||
mRanges[v + 1] = oldEnd;
|
||||
}
|
||||
|
||||
checkInternalConsistency();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RangeSet::toString () const
|
||||
{
|
||||
std::string ret;
|
||||
BOOST_FOREACH (value_type const & it, mRanges)
|
||||
{
|
||||
if (!ret.empty ())
|
||||
ret += ",";
|
||||
|
||||
if (it.first == it.second)
|
||||
ret += beast::lexicalCastThrow <std::string> ((it.first));
|
||||
else
|
||||
ret += beast::lexicalCastThrow <std::string> (it.first) + "-"
|
||||
+ beast::lexicalCastThrow <std::string> (it.second);
|
||||
}
|
||||
|
||||
if (ret.empty ())
|
||||
return "empty";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RangeSet::simplify ()
|
||||
{
|
||||
iterator it = mRanges.begin ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
iterator nit = it;
|
||||
|
||||
if (++nit == mRanges.end ())
|
||||
{
|
||||
checkInternalConsistency();
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->second >= (nit->first - 1))
|
||||
{
|
||||
// ranges overlap
|
||||
it->second = std::max(it->second, nit->second);
|
||||
mRanges.erase (nit);
|
||||
}
|
||||
else
|
||||
{
|
||||
it = nit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RangeSet::checkInternalConsistency () const noexcept
|
||||
{
|
||||
#if BEAST_DEBUG
|
||||
if (mRanges.size () > 1)
|
||||
{
|
||||
const_iterator const last = std::prev (mRanges.end ());
|
||||
|
||||
for (const_iterator cur = mRanges.begin (); cur != last; ++cur)
|
||||
{
|
||||
const_iterator const next = std::next (cur);
|
||||
|
||||
bassert (cur->first <= cur->second);
|
||||
|
||||
bassert (next->first <= next->second);
|
||||
|
||||
bassert (cur->second + 1 < next->first);
|
||||
}
|
||||
}
|
||||
else if (mRanges.size () == 1)
|
||||
{
|
||||
const_iterator const iter = mRanges.begin ();
|
||||
|
||||
bassert (iter->first <= iter->second);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RangeSet_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
RangeSet createPredefinedSet ()
|
||||
{
|
||||
RangeSet set;
|
||||
|
||||
// Set will include:
|
||||
// [ 0, 5]
|
||||
// [10,15]
|
||||
// [20,25]
|
||||
// etc...
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
set.setRange (10 * i, 10 * i + 5);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
void testMembership ()
|
||||
{
|
||||
testcase ("membership");
|
||||
|
||||
RangeSet r1, r2;
|
||||
|
||||
r1.setRange (1, 10);
|
||||
r1.clearValue (5);
|
||||
r1.setRange (11, 20);
|
||||
|
||||
r2.setRange (1, 4);
|
||||
r2.setRange (6, 10);
|
||||
r2.setRange (10, 20);
|
||||
|
||||
expect (!r1.hasValue (5));
|
||||
|
||||
expect (r2.hasValue (9));
|
||||
}
|
||||
|
||||
void testPrevMissing ()
|
||||
{
|
||||
testcase ("prevMissing");
|
||||
|
||||
RangeSet const set = createPredefinedSet ();
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
int const oneBelowRange = (10*(i/10))-1;
|
||||
|
||||
int const expectedPrevMissing =
|
||||
((i % 10) > 6) ? (i-1) : oneBelowRange;
|
||||
|
||||
expect (set.prevMissing (i) == expectedPrevMissing);
|
||||
}
|
||||
}
|
||||
|
||||
void run ()
|
||||
{
|
||||
testMembership ();
|
||||
|
||||
testPrevMissing ();
|
||||
|
||||
// TODO: Traverse functions must be tested
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(RangeSet,ripple_basics,ripple);
|
||||
|
||||
} // ripple
|
||||
|
||||
371
src/ripple/basics/impl/StringUtilities.cpp
Normal file
371
src/ripple/basics/impl/StringUtilities.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <cstdarg>
|
||||
|
||||
#include <ripple/basics/ToString.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// NIKB NOTE: This function is only used by strUnHex (std::string const& strSrc)
|
||||
// which results in a pointless copy from std::string into std::vector. Should
|
||||
// we just scrap this function altogether?
|
||||
int strUnHex (std::string& strDst, std::string const& strSrc)
|
||||
{
|
||||
std::string tmp;
|
||||
|
||||
tmp.reserve ((strSrc.size () + 1) / 2);
|
||||
|
||||
auto iter = strSrc.cbegin ();
|
||||
|
||||
if (strSrc.size () & 1)
|
||||
{
|
||||
int c = charUnHex (*iter);
|
||||
|
||||
if (c < 0)
|
||||
return -1;
|
||||
|
||||
tmp.push_back(c);
|
||||
++iter;
|
||||
}
|
||||
|
||||
while (iter != strSrc.cend ())
|
||||
{
|
||||
int cHigh = charUnHex (*iter);
|
||||
++iter;
|
||||
|
||||
if (cHigh < 0)
|
||||
return -1;
|
||||
|
||||
int cLow = charUnHex (*iter);
|
||||
++iter;
|
||||
|
||||
if (cLow < 0)
|
||||
return -1;
|
||||
|
||||
tmp.push_back (static_cast<char>((cHigh << 4) | cLow));
|
||||
}
|
||||
|
||||
strDst = std::move(tmp);
|
||||
|
||||
return strDst.size ();
|
||||
}
|
||||
|
||||
std::pair<Blob, bool> strUnHex (std::string const& strSrc)
|
||||
{
|
||||
std::string strTmp;
|
||||
|
||||
if (strUnHex (strTmp, strSrc) == -1)
|
||||
return std::make_pair (Blob (), false);
|
||||
|
||||
return std::make_pair(strCopy (strTmp), true);
|
||||
}
|
||||
|
||||
uint64_t uintFromHex (std::string const& strSrc)
|
||||
{
|
||||
uint64_t uValue (0);
|
||||
|
||||
if (strSrc.size () > 16)
|
||||
throw std::invalid_argument("overlong 64-bit value");
|
||||
|
||||
for (auto c : strSrc)
|
||||
{
|
||||
int ret = charUnHex (c);
|
||||
|
||||
if (ret == -1)
|
||||
throw std::invalid_argument("invalid hex digit");
|
||||
|
||||
uValue = (uValue << 4) | ret;
|
||||
}
|
||||
|
||||
return uValue;
|
||||
}
|
||||
|
||||
//
|
||||
// Misc string
|
||||
//
|
||||
|
||||
Blob strCopy (std::string const& strSrc)
|
||||
{
|
||||
Blob vucDst;
|
||||
|
||||
vucDst.resize (strSrc.size ());
|
||||
|
||||
std::copy (strSrc.begin (), strSrc.end (), vucDst.begin ());
|
||||
|
||||
return vucDst;
|
||||
}
|
||||
|
||||
std::string strCopy (Blob const& vucSrc)
|
||||
{
|
||||
std::string strDst;
|
||||
|
||||
strDst.resize (vucSrc.size ());
|
||||
|
||||
std::copy (vucSrc.begin (), vucSrc.end (), strDst.begin ());
|
||||
|
||||
return strDst;
|
||||
|
||||
}
|
||||
|
||||
extern std::string urlEncode (std::string const& strSrc)
|
||||
{
|
||||
std::string strDst;
|
||||
int iOutput = 0;
|
||||
int iSize = strSrc.length ();
|
||||
|
||||
strDst.resize (iSize * 3);
|
||||
|
||||
for (int iInput = 0; iInput < iSize; iInput++)
|
||||
{
|
||||
unsigned char c = strSrc[iInput];
|
||||
|
||||
if (c == ' ')
|
||||
{
|
||||
strDst[iOutput++] = '+';
|
||||
}
|
||||
else if (isalnum (c))
|
||||
{
|
||||
strDst[iOutput++] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
strDst[iOutput++] = '%';
|
||||
strDst[iOutput++] = charHex (c >> 4);
|
||||
strDst[iOutput++] = charHex (c & 15);
|
||||
}
|
||||
}
|
||||
|
||||
strDst.resize (iOutput);
|
||||
|
||||
return strDst;
|
||||
}
|
||||
|
||||
//
|
||||
// IP Port parsing
|
||||
//
|
||||
// <-- iPort: "" = -1
|
||||
// VFALCO TODO Make this not require boost... and especially boost::asio
|
||||
bool parseIpPort (std::string const& strSource, std::string& strIP, int& iPort)
|
||||
{
|
||||
boost::smatch smMatch;
|
||||
bool bValid = false;
|
||||
|
||||
static boost::regex reEndpoint ("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'");
|
||||
|
||||
if (boost::regex_match (strSource, smMatch, reEndpoint))
|
||||
{
|
||||
boost::system::error_code err;
|
||||
std::string strIPRaw = smMatch[1];
|
||||
std::string strPortRaw = smMatch[2];
|
||||
|
||||
boost::asio::ip::address addrIP = boost::asio::ip::address::from_string (strIPRaw, err);
|
||||
|
||||
bValid = !err;
|
||||
|
||||
if (bValid)
|
||||
{
|
||||
strIP = addrIP.to_string ();
|
||||
iPort = strPortRaw.empty () ? -1 : beast::lexicalCastThrow <int> (strPortRaw);
|
||||
}
|
||||
}
|
||||
|
||||
return bValid;
|
||||
}
|
||||
|
||||
// VFALCO TODO Callers should be using beast::URL and beast::ParsedURL, not this home-brew.
|
||||
//
|
||||
bool parseUrl (std::string const& strUrl, std::string& strScheme, std::string& strDomain, int& iPort, std::string& strPath)
|
||||
{
|
||||
// scheme://username:password@hostname:port/rest
|
||||
static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^:/]+)(?::(\\d+))?(/.*)?\\s*?\\'");
|
||||
boost::smatch smMatch;
|
||||
|
||||
bool bMatch = boost::regex_match (strUrl, smMatch, reUrl); // Match status code.
|
||||
|
||||
if (bMatch)
|
||||
{
|
||||
std::string strPort;
|
||||
|
||||
strScheme = smMatch[1];
|
||||
strDomain = smMatch[2];
|
||||
strPort = smMatch[3];
|
||||
strPath = smMatch[4];
|
||||
|
||||
boost::algorithm::to_lower (strScheme);
|
||||
|
||||
iPort = strPort.empty () ? -1 : beast::lexicalCast <int> (strPort);
|
||||
}
|
||||
|
||||
return bMatch;
|
||||
}
|
||||
|
||||
beast::StringPairArray parseDelimitedKeyValueString (beast::String parameters,
|
||||
beast::beast_wchar delimiter)
|
||||
{
|
||||
beast::StringPairArray keyValues;
|
||||
|
||||
while (parameters.isNotEmpty ())
|
||||
{
|
||||
beast::String pair;
|
||||
|
||||
{
|
||||
int const delimiterPos = parameters.indexOfChar (delimiter);
|
||||
|
||||
if (delimiterPos != -1)
|
||||
{
|
||||
pair = parameters.substring (0, delimiterPos);
|
||||
|
||||
parameters = parameters.substring (delimiterPos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = parameters;
|
||||
|
||||
parameters = beast::String::empty;
|
||||
}
|
||||
}
|
||||
|
||||
int const equalPos = pair.indexOfChar ('=');
|
||||
|
||||
if (equalPos != -1)
|
||||
{
|
||||
beast::String const key = pair.substring (0, equalPos);
|
||||
beast::String const value = pair.substring (equalPos + 1, pair.length ());
|
||||
|
||||
keyValues.set (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class StringUtilities_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void testUnHexSuccess (std::string strIn, std::string strExpected)
|
||||
{
|
||||
std::string strOut;
|
||||
|
||||
expect (strUnHex (strOut, strIn) == strExpected.length (),
|
||||
"strUnHex: parsing correct input failed");
|
||||
|
||||
expect (strOut == strExpected,
|
||||
"strUnHex: parsing doesn't produce expected result");
|
||||
}
|
||||
|
||||
void testUnHexFailure (std::string strIn)
|
||||
{
|
||||
std::string strOut;
|
||||
|
||||
expect (strUnHex (strOut, strIn) == -1,
|
||||
"strUnHex: parsing incorrect input succeeded");
|
||||
|
||||
expect (strOut.empty (),
|
||||
"strUnHex: parsing incorrect input returned data");
|
||||
}
|
||||
|
||||
void testUnHex ()
|
||||
{
|
||||
testcase ("strUnHex");
|
||||
|
||||
testUnHexSuccess ("526970706c6544", "RippleD");
|
||||
testUnHexSuccess ("A", "\n");
|
||||
testUnHexSuccess ("0A", "\n");
|
||||
testUnHexSuccess ("D0A", "\r\n");
|
||||
testUnHexSuccess ("0D0A", "\r\n");
|
||||
testUnHexSuccess ("200D0A", " \r\n");
|
||||
testUnHexSuccess ("282A2B2C2D2E2F29", "(*+,-./)");
|
||||
|
||||
// Check for things which contain some or only invalid characters
|
||||
testUnHexFailure ("123X");
|
||||
testUnHexFailure ("V");
|
||||
testUnHexFailure ("XRP");
|
||||
}
|
||||
|
||||
void testParseUrl ()
|
||||
{
|
||||
testcase ("parseUrl");
|
||||
|
||||
std::string strScheme;
|
||||
std::string strDomain;
|
||||
int iPort;
|
||||
std::string strPath;
|
||||
|
||||
unexpected (!parseUrl ("lower://domain", strScheme, strDomain, iPort, strPath),
|
||||
"parseUrl: lower://domain failed");
|
||||
|
||||
unexpected (strScheme != "lower",
|
||||
"parseUrl: lower://domain : scheme failed");
|
||||
|
||||
unexpected (strDomain != "domain",
|
||||
"parseUrl: lower://domain : domain failed");
|
||||
|
||||
unexpected (iPort != -1,
|
||||
"parseUrl: lower://domain : port failed");
|
||||
|
||||
unexpected (strPath != "",
|
||||
"parseUrl: lower://domain : path failed");
|
||||
|
||||
unexpected (!parseUrl ("UPPER://domain:234/", strScheme, strDomain, iPort, strPath),
|
||||
"parseUrl: UPPER://domain:234/ failed");
|
||||
|
||||
unexpected (strScheme != "upper",
|
||||
"parseUrl: UPPER://domain:234/ : scheme failed");
|
||||
|
||||
unexpected (iPort != 234,
|
||||
boost::str (boost::format ("parseUrl: UPPER://domain:234/ : port failed: %d") % iPort));
|
||||
|
||||
unexpected (strPath != "/",
|
||||
"parseUrl: UPPER://domain:234/ : path failed");
|
||||
|
||||
unexpected (!parseUrl ("Mixed://domain/path", strScheme, strDomain, iPort, strPath),
|
||||
"parseUrl: Mixed://domain/path failed");
|
||||
|
||||
unexpected (strScheme != "mixed",
|
||||
"parseUrl: Mixed://domain/path tolower failed");
|
||||
|
||||
unexpected (strPath != "/path",
|
||||
"parseUrl: Mixed://domain/path path failed");
|
||||
}
|
||||
|
||||
void testToString ()
|
||||
{
|
||||
testcase ("toString");
|
||||
auto result = to_string("hello");
|
||||
expect(result == "hello", result);
|
||||
}
|
||||
|
||||
void run ()
|
||||
{
|
||||
testParseUrl ();
|
||||
testUnHex ();
|
||||
testToString ();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(StringUtilities, ripple_basics, ripple);
|
||||
|
||||
} // ripple
|
||||
130
src/ripple/basics/impl/Sustain.cpp
Normal file
130
src/ripple/basics/impl/Sustain.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/ThreadName.h>
|
||||
|
||||
// For Sustain Linux variants
|
||||
// VFALCO TODO Rewrite Sustain to use beast::Process
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
namespace ripple {
|
||||
|
||||
#ifdef __unix__
|
||||
|
||||
static pid_t pManager = static_cast<pid_t> (0);
|
||||
static pid_t pChild = static_cast<pid_t> (0);
|
||||
|
||||
static void pass_signal (int a)
|
||||
{
|
||||
kill (pChild, a);
|
||||
}
|
||||
|
||||
static void stop_manager (int)
|
||||
{
|
||||
kill (pChild, SIGINT);
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
bool HaveSustain ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string StopSustain ()
|
||||
{
|
||||
if (getppid () != pManager)
|
||||
return std::string ();
|
||||
|
||||
kill (pManager, SIGHUP);
|
||||
return "Terminating monitor";
|
||||
}
|
||||
|
||||
std::string DoSustain (std::string logFile)
|
||||
{
|
||||
int childCount = 0;
|
||||
pManager = getpid ();
|
||||
signal (SIGINT, stop_manager);
|
||||
signal (SIGHUP, stop_manager);
|
||||
signal (SIGUSR1, pass_signal);
|
||||
signal (SIGUSR2, pass_signal);
|
||||
|
||||
while (1)
|
||||
{
|
||||
++childCount;
|
||||
pChild = fork ();
|
||||
|
||||
if (pChild == -1)
|
||||
_exit (0);
|
||||
|
||||
if (pChild == 0)
|
||||
{
|
||||
setCallingThreadName ("main");
|
||||
signal (SIGINT, SIG_DFL);
|
||||
signal (SIGHUP, SIG_DFL);
|
||||
signal (SIGUSR1, SIG_DFL);
|
||||
signal (SIGUSR2, SIG_DFL);
|
||||
return str (boost::format ("Launching child %d") % childCount);;
|
||||
}
|
||||
|
||||
setCallingThreadName (boost::str (boost::format ("#%d") % childCount).c_str ());
|
||||
|
||||
sleep (9);
|
||||
do
|
||||
{
|
||||
int i;
|
||||
sleep (1);
|
||||
waitpid (pChild, &i, 0);
|
||||
}
|
||||
while (kill (pChild, 0) == 0);
|
||||
|
||||
rename ("core", boost::str (boost::format ("core.%d") % static_cast<int> (pChild)).c_str ());
|
||||
if (!logFile.empty()) // FIXME: logFile hasn't been set yet
|
||||
rename (logFile.c_str(),
|
||||
boost::str (boost::format ("%s.%d")
|
||||
% logFile
|
||||
% static_cast<int> (pChild)).c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool HaveSustain ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::string DoSustain (std::string)
|
||||
{
|
||||
return std::string ();
|
||||
}
|
||||
std::string StopSustain ()
|
||||
{
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // ripple
|
||||
104
src/ripple/basics/impl/ThreadName.cpp
Normal file
104
src/ripple/basics/impl/ThreadName.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO TODO use beast::Thread::setCurrentThreadName() or something similar.
|
||||
|
||||
void setCallingThreadName (char const* threadName)
|
||||
{
|
||||
struct ThreadInfo
|
||||
{
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
};
|
||||
|
||||
ThreadInfo info;
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = GetCurrentThreadId ();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
// This is a VisualStudio specific exception
|
||||
RaiseException (0x406d1388, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
|
||||
}
|
||||
__except (EXCEPTION_CONTINUE_EXECUTION)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
#else
|
||||
|
||||
namespace ripple {
|
||||
|
||||
#ifdef PR_SET_NAME
|
||||
#define HAVE_NAME_THREAD
|
||||
extern void setCallingThreadName (const char* n)
|
||||
{
|
||||
static std::string pName;
|
||||
|
||||
if (pName.empty ())
|
||||
{
|
||||
std::ifstream cLine ("/proc/self/cmdline", std::ios::in);
|
||||
cLine >> pName;
|
||||
|
||||
if (pName.empty ())
|
||||
pName = "rippled";
|
||||
else
|
||||
{
|
||||
size_t zero = pName.find_first_of ('\0');
|
||||
|
||||
if ((zero != std::string::npos) && (zero != 0))
|
||||
pName = pName.substr (0, zero);
|
||||
|
||||
size_t slash = pName.find_last_of ('/');
|
||||
|
||||
if (slash != std::string::npos)
|
||||
pName = pName.substr (slash + 1);
|
||||
}
|
||||
|
||||
pName += " ";
|
||||
}
|
||||
|
||||
// VFALCO TODO Use beast::Thread::setCurrentThreadName here
|
||||
//
|
||||
prctl (PR_SET_NAME, (pName + n).c_str (), 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NAME_THREAD
|
||||
extern void setCallingThreadName (const char*)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
61
src/ripple/basics/impl/Time.cpp
Normal file
61
src/ripple/basics/impl/Time.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO TODO Tidy this up into a RippleTime object
|
||||
|
||||
//
|
||||
// Time support
|
||||
// We have our own epoch.
|
||||
//
|
||||
|
||||
boost::posix_time::ptime ptEpoch ()
|
||||
{
|
||||
return boost::posix_time::ptime (boost::gregorian::date (2000, boost::gregorian::Jan, 1));
|
||||
}
|
||||
|
||||
int iToSeconds (boost::posix_time::ptime ptWhen)
|
||||
{
|
||||
return ptWhen.is_not_a_date_time ()
|
||||
? -1
|
||||
: (ptWhen - ptEpoch ()).total_seconds ();
|
||||
}
|
||||
|
||||
// Convert our time in seconds to a ptime.
|
||||
boost::posix_time::ptime ptFromSeconds (int iSeconds)
|
||||
{
|
||||
return iSeconds < 0
|
||||
? boost::posix_time::ptime (boost::posix_time::not_a_date_time)
|
||||
: ptEpoch () + boost::posix_time::seconds (iSeconds);
|
||||
}
|
||||
|
||||
// Convert from our time to UNIX time in seconds.
|
||||
uint64_t utFromSeconds (int iSeconds)
|
||||
{
|
||||
boost::posix_time::time_duration tdDelta =
|
||||
boost::posix_time::ptime (boost::gregorian::date (2000, boost::gregorian::Jan, 1))
|
||||
- boost::posix_time::ptime (boost::gregorian::date (1970, boost::gregorian::Jan, 1))
|
||||
+ boost::posix_time::seconds (iSeconds)
|
||||
;
|
||||
|
||||
return tdDelta.total_seconds ();
|
||||
}
|
||||
|
||||
} // ripple
|
||||
80
src/ripple/basics/impl/UptimeTimer.cpp
Normal file
80
src/ripple/basics/impl/UptimeTimer.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/UptimeTimer.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
UptimeTimer::UptimeTimer ()
|
||||
: m_elapsedTime (0)
|
||||
, m_startTime (::time (0))
|
||||
, m_isUpdatingManually (false)
|
||||
{
|
||||
}
|
||||
|
||||
UptimeTimer::~UptimeTimer ()
|
||||
{
|
||||
}
|
||||
|
||||
int UptimeTimer::getElapsedSeconds () const
|
||||
{
|
||||
int result;
|
||||
|
||||
if (m_isUpdatingManually)
|
||||
{
|
||||
beast::memoryBarrier();
|
||||
result = m_elapsedTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// VFALCO TODO use time_t instead of int return
|
||||
result = static_cast <int> (::time (0) - m_startTime);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UptimeTimer::beginManualUpdates ()
|
||||
{
|
||||
//assert (!m_isUpdatingManually);
|
||||
|
||||
m_isUpdatingManually = true;
|
||||
}
|
||||
|
||||
void UptimeTimer::endManualUpdates ()
|
||||
{
|
||||
//assert (m_isUpdatingManually);
|
||||
|
||||
m_isUpdatingManually = false;
|
||||
}
|
||||
|
||||
void UptimeTimer::incrementElapsedTime ()
|
||||
{
|
||||
//assert (m_isUpdatingManually);
|
||||
++m_elapsedTime;
|
||||
}
|
||||
|
||||
UptimeTimer& UptimeTimer::getInstance ()
|
||||
{
|
||||
static UptimeTimer instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
Reference in New Issue
Block a user