diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj
index dc35d97608..de1f84bf82 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj
+++ b/Builds/VisualStudio2012/RippleD.vcxproj
@@ -301,6 +301,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -1417,6 +1423,7 @@
+
diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters
index 1226f51fe4..91219499c1 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters
@@ -882,6 +882,9 @@
[1] Ripple\ripple_app\main
+
+ [1] Ripple\ripple_app\network
+
@@ -1670,6 +1673,9 @@
[2] Build
+
+ [1] Ripple\ripple_app\network
+
diff --git a/Notes/VFALCO_TODO.txt b/Notes/VFALCO_TODO.txt
index 7acb0598a8..331207b8b3 100644
--- a/Notes/VFALCO_TODO.txt
+++ b/Notes/VFALCO_TODO.txt
@@ -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
diff --git a/SConstruct b/SConstruct
index 043423c56d..8dae719925 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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:
diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp
index 6737f9db08..68d864d509 100644
--- a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp
+++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp
@@ -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 ();
diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h
index 130524ea08..f65a39ad39 100644
--- a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h
+++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h
@@ -87,11 +87,7 @@ public:
FatalError (char const* message, char const* fileName, int lineNumber);
private:
- typedef CriticalSection LockType;
-
static Static::Storage , FatalError> s_reporter;
-
- LockType m_mutex;
};
#endif
diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp
index 5e3972347b..5a6c56674a 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp
+++ b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp
@@ -227,6 +227,7 @@ bool Process::openDocument (const String& fileName, const String& parameters)
{
const LocalRef t (javaString (fileName));
android.activity.callVoidMethod (BeastAppActivity.launchURL, t.get());
+ return true;
}
void File::revealToUser() const
diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp
index d2d236a180..275fd6e114 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp
+++ b/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp
@@ -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());
}
diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp
index 1dd9a5bc38..fe66fa6df6 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp
+++ b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp
@@ -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));
}
diff --git a/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp
index 32a6d92e7f..5fce6d211d 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp
+++ b/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp
@@ -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;
diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm
index 4834c5fb56..9d43f5acf9 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm
+++ b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm
@@ -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)
diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp
index 5ba5a1f3b6..c4f1f8ca4e 100644
--- a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp
+++ b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp
@@ -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);
diff --git a/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp b/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp
index 2a15c9315d..789cc46f4c 100644
--- a/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp
+++ b/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp
@@ -121,7 +121,7 @@ static void findIPAddresses (int sock, Array& 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];
diff --git a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h
index 081a7b037b..2b911bf180 100644
--- a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h
+++ b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h
@@ -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
- void readTypeInto (T* p)
+ bool readTypeInto (T* p)
{
- *p = readType ();
+ if (getNumBytesRemaining () >= sizeof (T))
+ {
+ *p = readType ();
+ 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
- void readTypeBigEndianInto (T* p)
+ bool readTypeBigEndianInto (T* p)
{
- *p = readTypeBigEndian ();
+ if (getNumBytesRemaining () >= sizeof (T))
+ {
+ *p = readTypeBigEndian ();
+ return true;
+ }
+ return false;
}
//==============================================================================
diff --git a/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h
index d3e0d0b8d5..038feab6e9 100644
--- a/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h
+++ b/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h
@@ -53,7 +53,7 @@ public:
*/
MemoryInputStream (const void* sourceData,
size_t sourceDataSize,
- bool keepInternalCopyOfData);
+ bool keepInternalCopyOfData = false);
/** Creates a MemoryInputStream.
diff --git a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp
index 1e50c7176d..0098e33d0b 100644
--- a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp
+++ b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp
@@ -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()
diff --git a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h
index 02a76b21ea..1575611976 100644
--- a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h
+++ b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h
@@ -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();
};
diff --git a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp
index a2f7289743..0a5fffae4e 100644
--- a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp
+++ b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp
@@ -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 (s);
+}
+
static CurrentThreadHolder::Ptr getCurrentThreadHolder()
{
static CurrentThreadHolder::Ptr currentThreadHolder;
- SpinLock::ScopedLockType lock (*reinterpret_cast (currentThreadHolderLock));
+ SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock));
if (currentThreadHolder == nullptr)
currentThreadHolder = new CurrentThreadHolder();
diff --git a/modules/ripple_app/basics/ripple_BuildInfo.cpp b/modules/ripple_app/basics/ripple_BuildInfo.cpp
index b0054b89b5..c0c440e8ed 100644
--- a/modules/ripple_app/basics/ripple_BuildInfo.cpp
+++ b/modules/ripple_app/basics/ripple_BuildInfo.cpp
@@ -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 ();
}
diff --git a/modules/ripple_app/network/ripple_ProxyHandshake.cpp b/modules/ripple_app/network/ripple_ProxyHandshake.cpp
new file mode 100644
index 0000000000..c3dba646ee
--- /dev/null
+++ b/modules/ripple_app/network/ripple_ProxyHandshake.cpp
@@ -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 (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 (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;
diff --git a/modules/ripple_app/network/ripple_ProxyHandshake.h b/modules/ripple_app/network/ripple_ProxyHandshake.h
new file mode 100644
index 0000000000..d9bd6efa3c
--- /dev/null
+++ b/modules/ripple_app/network/ripple_ProxyHandshake.h
@@ -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
diff --git a/modules/ripple_app/ripple_app.cpp b/modules/ripple_app/ripple_app.cpp
index 9e24a0e63b..469bccd3bd 100644
--- a/modules/ripple_app/ripple_app.cpp
+++ b/modules/ripple_app/ripple_app.cpp
@@ -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