Clean up and restructure sources

This commit is contained in:
Vinnie Falco
2014-09-16 14:03:58 -07:00
parent 1dcd06a1c1
commit 4239880acb
522 changed files with 3264 additions and 3400 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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