Merge branch 'develop' of github.com:ripple/rippled into develop

This commit is contained in:
JoelKatz
2013-07-31 20:32:52 -07:00
22 changed files with 630 additions and 83 deletions

View File

@@ -301,6 +301,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\network\ripple_ProxyHandshake.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\network\ripple_WSHandler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -1417,6 +1423,7 @@
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_ProofOfWorkFactory.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_SerializedLedger.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_SerializedTransaction.h" />
<ClInclude Include="..\..\modules\ripple_app\network\ripple_ProxyHandshake.h" />
<ClInclude Include="..\..\modules\ripple_app\network\ripple_WSHandler.h" />
<ClInclude Include="..\..\modules\ripple_app\network\WSConnection.h" />
<ClInclude Include="..\..\modules\ripple_app\network\WSDoor.h" />

View File

@@ -882,6 +882,9 @@
<ClCompile Include="..\..\modules\ripple_app\main\ripple_FatalErrorReporter.cpp">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\network\ripple_ProxyHandshake.cpp">
<Filter>[1] Ripple\ripple_app\network</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h">
@@ -1670,6 +1673,9 @@
<ClInclude Include="..\..\BeastConfig.h">
<Filter>[2] Build</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\network\ripple_ProxyHandshake.h">
<Filter>[1] Ripple\ripple_app\network</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\modules\ripple_data\protocol\ripple.proto">

View File

@@ -7,6 +7,7 @@ REMINDER: KEEP CHANGE LOG UP TO DATE
Vinnie's List: Changes day to day, descending priority
(Items marked '*' can be handled by others.)
- Emergency implement PROXY protcol
- Get rid of boost::filesystem
- Deeply create directories specified in config settings
- Finish unit tests and code for Validators

View File

@@ -53,9 +53,9 @@ else:
env.Replace(CTAGS = CTAGS, CTAGSOPTIONS = '--tag-relative')
# Use openssl
env.ParseConfig('pkg-config --cflags --libs openssl')
env.ParseConfig('pkg-config --static --cflags --libs openssl')
# Use protobuf
env.ParseConfig('pkg-config --cflags --libs protobuf')
env.ParseConfig('pkg-config --static --cflags --libs protobuf')
# Beast uses kvm on FreeBSD
if FreeBSD:

View File

@@ -31,7 +31,11 @@ void FatalError::resetReporter (Reporter& reporter)
FatalError::FatalError (char const* message, char const* fileName, int lineNumber)
{
LockType::ScopedLockType lock (m_mutex);
typedef CriticalSection LockType;
static LockType s_mutex;
LockType::ScopedLockType lock (s_mutex);
String const backtraceString = SystemStats::getStackBacktrace ();

View File

@@ -87,11 +87,7 @@ public:
FatalError (char const* message, char const* fileName, int lineNumber);
private:
typedef CriticalSection LockType;
static Static::Storage <Atomic <Reporter*>, FatalError> s_reporter;
LockType m_mutex;
};
#endif

View File

@@ -227,6 +227,7 @@ bool Process::openDocument (const String& fileName, const String& parameters)
{
const LocalRef<jstring> t (javaString (fileName));
android.activity.callVoidMethod (BeastAppActivity.launchURL, t.get());
return true;
}
void File::revealToUser() const

View File

@@ -23,5 +23,5 @@
void Logger::outputDebugString (const String& text)
{
__android_log_print (ANDROID_LOG_INFO, "BEAST", text.toUTF8());
__android_log_print (ANDROID_LOG_INFO, "BEAST", "%", text.toUTF8().getAddress());
}

View File

@@ -262,14 +262,8 @@ String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocale
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
//==============================================================================
SystemStats::CPUFlags::CPUFlags()
void CPUInformation::initialise() noexcept
{
// TODO
hasMMX = false;
hasSSE = false;
hasSSE2 = false;
has3DNow = false;
numCpus = bmax (1, sysconf (_SC_NPROCESSORS_ONLN));
}

View File

@@ -127,12 +127,13 @@ String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICA
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
//==============================================================================
SystemStats::CPUFlags::CPUFlags()
void CPUInformation::initialise() noexcept
{
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
hasMMX = flags.contains ("mmx");
hasSSE = flags.contains ("sse");
hasSSE2 = flags.contains ("sse2");
hasMMX = flags.contains ("mmx");
hasSSE = flags.contains ("sse");
hasSSE2 = flags.contains ("sse2");
hasSSE3 = flags.contains ("sse3");
has3DNow = flags.contains ("3dnow");
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;

View File

@@ -64,21 +64,17 @@ namespace SystemStatsHelpers
}
//==============================================================================
SystemStats::CPUFlags::CPUFlags()
void CPUInformation::initialise() noexcept
{
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
uint32 familyModel = 0, extFeatures = 0, features = 0, dummy = 0;
SystemStatsHelpers::doCPUID (familyModel, extFeatures, dummy, features, 1);
uint32 a = 0, b = 0, d = 0, c = 0;
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
hasMMX = (features & (1u << 23)) != 0;
hasSSE = (features & (1u << 25)) != 0;
hasSSE2 = (features & (1u << 26)) != 0;
has3DNow = (extFeatures & (1u << 31)) != 0;
#else
hasMMX = false;
hasSSE = false;
hasSSE2 = false;
has3DNow = false;
hasMMX = (d & (1u << 23)) != 0;
hasSSE = (d & (1u << 25)) != 0;
hasSSE2 = (d & (1u << 26)) != 0;
has3DNow = (b & (1u << 31)) != 0;
hasSSE3 = (c & (1u << 0)) != 0;
#endif
#if BEAST_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)

View File

@@ -99,16 +99,13 @@ String SystemStats::getCpuVendor()
//==============================================================================
SystemStats::CPUFlags::CPUFlags()
void CPUInformation::initialise() noexcept
{
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
#ifdef PF_AMD3D_INSTRUCTIONS_AVAILABLE
has3DNow = IsProcessorFeaturePresent (PF_AMD3D_INSTRUCTIONS_AVAILABLE) != 0;
#else
has3DNow = IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0;
#endif
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE3 = IsProcessorFeaturePresent (13 /*PF_SSE3_INSTRUCTIONS_AVAILABLE*/) != 0;
has3DNow = IsProcessorFeaturePresent (7 /*PF_AMD3D_INSTRUCTIONS_AVAILABLE*/) != 0;
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);

View File

@@ -121,7 +121,7 @@ static void findIPAddresses (int sock, Array<IPAddress>& result)
cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
}
#else
for (int i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
for (size_t i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
{
const ifreq& item = cfg.ifc_req[i];

View File

@@ -239,14 +239,19 @@ public:
/** Reads a type using a template specialization.
The variable is passed as a parameter so that the template type
can be deduced.
can be deduced. The return value indicates whether or not there
was sufficient data in the stream to read the value.
This is useful when doing template meta-programming.
*/
template <class T>
void readTypeInto (T* p)
bool readTypeInto (T* p)
{
*p = readType <T> ();
if (getNumBytesRemaining () >= sizeof (T))
{
*p = readType <T> ();
return true;
}
return false;
}
/** Reads a type from a big endian stream using a template specialization.
@@ -262,14 +267,18 @@ public:
/** Reads a type using a template specialization.
The variable is passed as a parameter so that the template type
can be deduced.
This is useful when doing template meta-programming.
can be deduced. The return value indicates whether or not there
was sufficient data in the stream to read the value.
*/
template <class T>
void readTypeBigEndianInto (T* p)
bool readTypeBigEndianInto (T* p)
{
*p = readTypeBigEndian <T> ();
if (getNumBytesRemaining () >= sizeof (T))
{
*p = readTypeBigEndian <T> ();
return true;
}
return false;
}
//==============================================================================

View File

@@ -53,7 +53,7 @@ public:
*/
MemoryInputStream (const void* sourceData,
size_t sourceDataSize,
bool keepInternalCopyOfData);
bool keepInternalCopyOfData = false);
/** Creates a MemoryInputStream.

View File

@@ -21,12 +21,6 @@
*/
//==============================================================================
const SystemStats::CPUFlags& SystemStats::getCPUFlags()
{
static CPUFlags cpuFlags;
return cpuFlags;
}
String SystemStats::getBeastVersion()
{
// Some basic tests, to keep an eye on things and make sure these types work ok
@@ -62,6 +56,34 @@ String SystemStats::getBeastVersion()
static BeastVersionPrinter beastVersionPrinter;
#endif
//==============================================================================
struct CPUInformation
{
CPUInformation() noexcept
: numCpus (0), hasMMX (false), hasSSE (false),
hasSSE2 (false), hasSSE3 (false), has3DNow (false)
{
initialise();
}
void initialise() noexcept;
int numCpus;
bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow;
};
static const CPUInformation& getCPUInformation() noexcept
{
static CPUInformation info;
return info;
}
int SystemStats::getNumCpus() noexcept { return getCPUInformation().numCpus; }
bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; }
bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; }
bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; }
bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; }
bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }
//==============================================================================
String SystemStats::getStackBacktrace()

View File

@@ -121,8 +121,8 @@ public:
//==============================================================================
// CPU and memory information..
/** Returns the number of CPUs. */
static int getNumCpus() noexcept { return getCPUFlags().numCpus; }
/** Returns the number of CPU cores. */
static int getNumCpus() noexcept;
/** Returns the approximate CPU speed.
@returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on
@@ -135,17 +135,11 @@ public:
*/
static String getCpuVendor();
/** Checks whether Intel MMX instructions are available. */
static bool hasMMX() noexcept { return getCPUFlags().hasMMX; }
/** Checks whether Intel SSE instructions are available. */
static bool hasSSE() noexcept { return getCPUFlags().hasSSE; }
/** Checks whether Intel SSE2 instructions are available. */
static bool hasSSE2() noexcept { return getCPUFlags().hasSSE2; }
/** Checks whether AMD 3DNOW instructions are available. */
static bool has3DNow() noexcept { return getCPUFlags().has3DNow; }
static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */
static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */
static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */
static bool hasSSE3() noexcept; /**< Returns true if Intel SSE2 instructions are available. */
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */
//==============================================================================
/** Finds out how much RAM is in the machine.
@@ -179,19 +173,8 @@ public:
private:
//==============================================================================
struct CPUFlags
{
CPUFlags();
int numCpus;
bool hasMMX : 1;
bool hasSSE : 1;
bool hasSSE2 : 1;
bool has3DNow : 1;
};
SystemStats();
static const CPUFlags& getCPUFlags();
};

View File

@@ -58,10 +58,15 @@ struct CurrentThreadHolder : public SharedObject
static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
static SpinLock* castToSpinLockWithoutAliasingWarning (void* s)
{
return static_cast<SpinLock*> (s);
}
static CurrentThreadHolder::Ptr getCurrentThreadHolder()
{
static CurrentThreadHolder::Ptr currentThreadHolder;
SpinLock::ScopedLockType lock (*reinterpret_cast <SpinLock*> (currentThreadHolderLock));
SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock));
if (currentThreadHolder == nullptr)
currentThreadHolder = new CurrentThreadHolder();

View File

@@ -209,7 +209,7 @@ std::string BuildInfo::Protocol::toStdString () const noexcept
{
String s;
s << String (vmajor) << "." << "vminor";
s << String (vmajor) << "." << String (vminor);
return s.toStdString ();
}

View File

@@ -0,0 +1,371 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
ProxyHandshake::ProxyHandshake (bool expectHandshake)
: m_status (expectHandshake ? statusHandshake : statusNone)
, m_gotCR (false)
{
m_buffer.preallocateBytes (maxVersion1Bytes);
}
ProxyHandshake::~ProxyHandshake ()
{
}
std::size_t ProxyHandshake::feed (void const* inputBuffer, size_t inputBytes)
{
std::size_t bytesConsumed = 0;
char const* p = static_cast <char const*> (inputBuffer);
if (m_status == statusHandshake)
{
if (! m_gotCR)
{
while (inputBytes > 0 && m_buffer.length () < maxVersion1Bytes - 1)
{
beast_wchar c = *p++;
++bytesConsumed;
--inputBytes;
m_buffer += c;
if (c == '\r')
{
m_gotCR = true;
break;
}
else if (c == '\n')
{
m_status = statusFailed;
}
}
if (m_buffer.length () > maxVersion1Bytes - 1)
{
m_status = statusFailed;
}
}
}
if (m_status == statusHandshake)
{
if (inputBytes > 0 && m_gotCR)
{
bassert (m_buffer.length () < maxVersion1Bytes);
char const lf ('\n');
if (*p == lf)
{
++bytesConsumed;
--inputBytes;
m_buffer += lf;
parseLine ();
}
else
{
m_status = statusFailed;
}
}
}
return bytesConsumed;
}
void ProxyHandshake::parseLine ()
{
Version1 p;
bool success = p.parse (m_buffer.getCharPointer (), m_buffer.length ());
if (success)
{
m_endpoints = p.endpoints;
m_status = statusOk;
}
else
{
m_status = statusFailed;
}
}
int ProxyHandshake::indexOfFirstNonNumber (String const& input)
{
bassert (input.length () > 0);
int i = 0;
for (; i < input.length (); ++i)
{
if (! CharacterFunctions::isDigit (input [i]))
break;
}
return i;
}
bool ProxyHandshake::chop (String const& what, String& input)
{
if (input.startsWith (what))
{
input = input.substring (what.length ());
return true;
}
return false;
}
bool ProxyHandshake::chopUInt (int* value, int limit, String& input)
{
if (input.length () <= 0)
return false;
String const s = input.substring (0, indexOfFirstNonNumber (input));
if (s.length () <= 0)
return false;
int const n = s.getIntValue ();
// Leading zeroes disallowed as per spec, to prevent confusion with octal
if (String (n) != s)
return false;
if (n < 0 || n > limit)
return false;
input = input.substring (s.length ());
*value = n;
return true;
}
//------------------------------------------------------------------------------
/*
steps:
Proxy protocol lets us filter attackers by learning the source ip and port
1. Determine if we should use the proxy on a connection
- Port just for proxy protocol connections
- Filter on source IPs
2. Read a line from the connection to get the proxy information
3. Parse the line (human or binary?)
4. Code Interface to retrieve proxy information (ip/port) on connection
*/
ProxyHandshake::Version1::Version1 ()
{
}
bool ProxyHandshake::IPv4::Addr::chop (String& input)
{
if (!ProxyHandshake::chopUInt (&a, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&b, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&c, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&d, 255, input))
return false;
return true;
}
bool ProxyHandshake::Version1::parse (void const* headerData, size_t headerBytes)
{
String input (static_cast <CharPointer_UTF8::CharType const*> (headerData), headerBytes);
if (input.length () < 2)
return false;
if (! input.endsWith ("\r\n"))
return false;
input = input.dropLastCharacters (2);
if (! ProxyHandshake::chop ("PROXY ", input))
return false;
if (ProxyHandshake::chop ("UNKNOWN", input))
{
endpoints.proto = protoUnknown;
input = "";
}
else
{
if (ProxyHandshake::chop ("TCP4 ", input))
{
endpoints.proto = protoTcp4;
if (! endpoints.ipv4.sourceAddr.chop (input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! endpoints.ipv4.destAddr.chop (input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! ProxyHandshake::chopUInt (&endpoints.ipv4.sourcePort, 65535, input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! ProxyHandshake::chopUInt (&endpoints.ipv4.destPort, 65535, input))
return false;
}
else if (ProxyHandshake::chop ("TCP6 ", input))
{
endpoints.proto = protoTcp6;
//bassertfalse;
return false;
}
else
{
return false;
}
}
// Can't have anything extra between the last port number and the CRLF
if (input.length () > 0)
return false;
return true;
}
//------------------------------------------------------------------------------
class ProxyHandshakeTests : public UnitTest
{
public:
ProxyHandshakeTests () : UnitTest ("ProxyHandshake", "ripple", runManual)
{
}
static std::string goodIpv4 ()
{
return "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; // 56 chars
}
static std::string goodIpv6 ()
{
return "PROXY TCP6 fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
//1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 4 (104 chars)
}
static std::string goodUnknown ()
{
return "PROXY UNKNOWN\r\n";
}
static std::string goodUnknownBig ()
{
return "PROXY UNKNOWN fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
//1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 7 (107 chars)
}
void testHandshake (std::string const& s, bool shouldSucceed)
{
if (s.size () > 1)
{
ProxyHandshake h (true);
expect (h.getStatus () == ProxyHandshake::statusHandshake);
for (int i = 0; i < s.size () && h.getStatus () == ProxyHandshake::statusHandshake ; ++i)
{
std::size_t const bytesConsumed = h.feed (& s[i], 1);
if (i != s.size () - 1)
expect (h.getStatus () == ProxyHandshake::statusHandshake);
expect (bytesConsumed == 1);
}
if (shouldSucceed)
{
expect (h.getStatus () == ProxyHandshake::statusOk);
}
else
{
expect (h.getStatus () == ProxyHandshake::statusFailed);
}
}
else
{
bassertfalse;
}
}
void testVersion1String (std::string const& s, bool shouldSucceed)
{
ProxyHandshake::Version1 p;
if (shouldSucceed)
{
expect (p.parse (s.c_str (), s.size ()));
}
else
{
unexpected (p.parse (s.c_str (), s.size ()));
}
for (int i = 1; i < s.size () - 1; ++i)
{
String const partial = String (s).dropLastCharacters (i);
std::string ss (partial.toStdString ());
expect (! p.parse (ss.c_str (), ss.size ()));
}
testHandshake (s, shouldSucceed);
}
void testVersion1 ()
{
beginTestCase ("version1");
testVersion1String (goodIpv4 (), true);
testVersion1String (goodIpv6 (), false);
testVersion1String (goodUnknown (), true);
testVersion1String (goodUnknownBig (), true);
}
void runTest ()
{
testVersion1 ();
}
};
static ProxyHandshakeTests proxyHandshakeTests;

View File

@@ -0,0 +1,151 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_PROXYYHANDSHAKE_H_INCLUDED
#define RIPPLE_PROXYYHANDSHAKE_H_INCLUDED
/** PROXY protocol handshake state machine.
The PROXY Protocol:
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
*/
class ProxyHandshake
{
public:
/** Status of the handshake state machine. */
enum Status
{
statusNone, // No handshake expected
statusHandshake, // Handshake in progress
statusFailed, // Handshake failed
statusOk, // Handshake succeeded
};
enum Proto
{
protoTcp4,
protoTcp6,
protoUnknown
};
/** PROXY information for IPv4 families. */
struct IPv4
{
struct Addr
{
int a;
int b;
int c;
int d;
bool chop (String& input);
};
Addr sourceAddr;
Addr destAddr;
int sourcePort;
int destPort;
};
/** PROXY information for IPv6 families. */
struct IPv6
{
struct Addr
{
int a;
int b;
int c;
int d;
};
Addr sourceAddr;
Addr destAddr;
int sourcePort;
int destPort;
};
/** Fully decoded PROXY information. */
struct Endpoints
{
Endpoints ()
: proto (protoUnknown)
{
}
Proto proto;
IPv4 ipv4; // valid if proto == protoTcp4
IPv6 ipv6; // valid if proto == protoTcp6;
};
//--------------------------------------------------------------------------
/** Parser for PROXY version 1. */
struct Version1
{
enum
{
// Maximum input buffer size needed, including a null
// terminator, as per the PROXY protocol specification.
maxBufferBytes = 108
};
Endpoints endpoints;
Version1 ();
/** Parse the header.
@param rawHeader a pointer to the header data
@return `true` If it was parsed successfully.
*/
bool parse (void const* headerData, size_t headerBytes);
};
//--------------------------------------------------------------------------
/** Create the handshake state.
If a handshake is expected, then it is required.
@param wantHandshake `false` to skip handshaking.
*/
explicit ProxyHandshake (bool expectHandshake = false);
~ProxyHandshake ();
inline Status getStatus () const noexcept
{
return m_status;
}
inline Endpoints const& getEndpoints () const noexcept
{
return m_endpoints;
};
/** Feed the handshaking state engine.
@return The number of bytes consumed in the input buffer.
*/
std::size_t feed (void const* inputBuffer, std::size_t inputBytes);
// Utility functions used by parsers
static int indexOfFirstNonNumber (String const& input);
static bool chop (String const& what, String& input);
static bool chopUInt (int* value, int limit, String& input);
private:
void parseLine ();
private:
enum
{
maxVersion1Bytes = 107 // including crlf, not including null term
};
Status m_status;
String m_buffer;
bool m_gotCR;
Endpoints m_endpoints;
};
#endif

View File

@@ -239,6 +239,8 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#include "network/ripple_ProxyHandshake.h" // private?
//------------------------------------------------------------------------------
#if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1
@@ -326,6 +328,7 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength)
#include "tx/Transactor.cpp"
#include "network/WSConnection.cpp"
#include "network/WSDoor.cpp"
#include "network/ripple_ProxyHandshake.cpp"
#endif