mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 19:45:53 +00:00
HTTP handshake in peer protocol (RIPD-351):
* New I/O paths for client and server role * New handshake_analyzer detects the peer protocol * New basic_message class for parsing and storing HTTP messages * Conditional compilation for selective feature enabling. * Server supports both current handshake and HTTP handshake
This commit is contained in:
@@ -3105,6 +3105,8 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\PeerImp.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\peer_info.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\peer_protocol_detector.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\Tuning.h">
|
||||
@@ -3121,6 +3123,9 @@
|
||||
</ClInclude>
|
||||
<None Include="..\..\src\ripple\overlay\README.md">
|
||||
</None>
|
||||
<ClCompile Include="..\..\src\ripple\overlay\tests\peer_info.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\peerfinder\api\Callback.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\peerfinder\api\Config.h">
|
||||
|
||||
@@ -463,6 +463,9 @@
|
||||
<Filter Include="ripple\overlay\impl">
|
||||
<UniqueIdentifier>{07E4BC73-2B68-D0D1-D922-FEBBB573F503}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\overlay\tests">
|
||||
<UniqueIdentifier>{630E81FA-2122-38EA-81BD-636140BF270C}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\peerfinder">
|
||||
<UniqueIdentifier>{186385AD-A056-FA3A-7E0E-759EB55E9EAB}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -4281,6 +4284,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\PeerImp.h">
|
||||
<Filter>ripple\overlay\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\peer_info.h">
|
||||
<Filter>ripple\overlay\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\overlay\impl\peer_protocol_detector.h">
|
||||
<Filter>ripple\overlay\impl</Filter>
|
||||
</ClInclude>
|
||||
@@ -4305,6 +4311,9 @@
|
||||
<None Include="..\..\src\ripple\overlay\README.md">
|
||||
<Filter>ripple\overlay</Filter>
|
||||
</None>
|
||||
<ClCompile Include="..\..\src\ripple\overlay\tests\peer_info.test.cpp">
|
||||
<Filter>ripple\overlay\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\peerfinder\api\Callback.h">
|
||||
<Filter>ripple\peerfinder\api</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -220,11 +220,17 @@
|
||||
#define RIPPLE_SINGLE_IO_SERVICE_THREAD 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_STRUCTURED_OVERLAY
|
||||
Enables Structured Overlay support (unfinished)
|
||||
/** Config: RIPPLE_STRUCTURED_OVERLAY_CLIENT
|
||||
RIPPLE_STRUCTURED_OVERLAY_SERVER
|
||||
Enables Structured Overlay support for the client or server roles.
|
||||
This feature is currently in development:
|
||||
https://ripplelabs.atlassian.net/browse/RIPD-157
|
||||
*/
|
||||
#ifndef RIPPLE_STRUCTURED_OVERLAY
|
||||
#define RIPPLE_STRUCTURED_OVERLAY 0
|
||||
#ifndef RIPPLE_STRUCTURED_OVERLAY_CLIENT
|
||||
#define RIPPLE_STRUCTURED_OVERLAY_CLIENT 0
|
||||
#endif
|
||||
#ifndef RIPPLE_STRUCTURED_OVERLAY_SERVER
|
||||
#define RIPPLE_STRUCTURED_OVERLAY_SERVER 1
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_ASYNC_RPC_HANDLER
|
||||
|
||||
@@ -21,6 +21,39 @@ establishes, receives, and maintains connections to peers. Protocol
|
||||
messages are exchanged between peers and serialized using
|
||||
[_Google Protocol Buffers_][protocol_buffers].
|
||||
|
||||
### Structure
|
||||
|
||||
Each connection between peers is identified by its connection type, which
|
||||
affects the behavior of message routing:
|
||||
|
||||
* Leaf
|
||||
|
||||
* Peer
|
||||
|
||||
## Roles
|
||||
|
||||
Depending on the type of connection desired, the peers will modify their
|
||||
behavior according to certain roles:
|
||||
|
||||
### Leaf or Superpeer
|
||||
|
||||
A peer in the leaf role does not route messages. In the superpeer role, a
|
||||
peer accepts incoming connections from other leaves and superpeers up to the
|
||||
configured slot limit. It also routes messages. For a particular connection,
|
||||
the choice of leaf or superpeer is mutually exclusive. However, a peer can
|
||||
operate in both the leaf and superpeer role for different connections. One of
|
||||
the requirements
|
||||
|
||||
### Client Handler
|
||||
|
||||
While not part of the responsibilities of the Overlay module, a peer
|
||||
operating in the Client Handler role accepts incoming connections from clients
|
||||
and services them through the JSON-RPC interface. A peer can operate in either
|
||||
the leaf or superpeer roles while also operating as a client handler.
|
||||
|
||||
|
||||
|
||||
|
||||
## Handshake
|
||||
|
||||
To establish a protocol connection, a peer makes an outgoing TLS encrypted
|
||||
@@ -128,6 +161,13 @@ Protocol-Session-Cookie: 71ED064155FFADFA38782C5E0158CB26
|
||||
|
||||
This field must be present (TODO)
|
||||
|
||||
* _User Defined_
|
||||
|
||||
The rippled operator may specify additional, optional fields and values
|
||||
through the configuration. These headers will be transmitted in the
|
||||
corresponding request or response messages.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[overlay_network]: http://en.wikipedia.org/wiki/Overlay_network
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,6 @@
|
||||
#include <ripple/common/MultiSocket.h>
|
||||
#include <ripple/nodestore/Database.h>
|
||||
#include <ripple/overlay/predicates.h>
|
||||
#include <ripple/overlay/impl/basic_message.h>
|
||||
#include <ripple/overlay/impl/message_name.h>
|
||||
#include <ripple/overlay/impl/message_stream.h>
|
||||
#include <ripple/overlay/impl/OverlayImpl.h>
|
||||
@@ -40,7 +39,7 @@
|
||||
|
||||
#include <beast/asio/IPAddressConversion.h>
|
||||
#include <beast/asio/placeholders.h>
|
||||
#include <beast/http/message_parser.h>
|
||||
#include <beast/http/basic_message.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -80,58 +79,6 @@ private:
|
||||
/** The length of the smallest valid finished message */
|
||||
static const size_t sslMinimumFinishedLength = 12;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/** We have accepted an inbound connection.
|
||||
|
||||
The connection state transitions from `stateConnect` to `stateConnected`
|
||||
as `stateConnect`.
|
||||
*/
|
||||
void accept ()
|
||||
{
|
||||
m_journal.info << "Accepted " << m_remoteAddress;
|
||||
|
||||
m_socket->set_verify_mode (boost::asio::ssl::verify_none);
|
||||
m_socket->async_handshake (
|
||||
boost::asio::ssl::stream_base::server,
|
||||
m_strand.wrap (std::bind (
|
||||
&PeerImp::handleStart,
|
||||
std::static_pointer_cast <PeerImp> (shared_from_this ()),
|
||||
beast::asio::placeholders::error)));
|
||||
}
|
||||
|
||||
/** Attempt an outbound connection.
|
||||
|
||||
The connection may fail (for a number of reasons) and we do not know
|
||||
what will happen at this point.
|
||||
|
||||
The connection state does not transition with this function and remains
|
||||
as `stateConnecting`.
|
||||
*/
|
||||
void connect ()
|
||||
{
|
||||
m_journal.info << "Connecting to " << m_remoteAddress;
|
||||
|
||||
boost::system::error_code err;
|
||||
|
||||
m_timer.expires_from_now (nodeVerifySeconds, err);
|
||||
|
||||
m_timer.async_wait (m_strand.wrap (std::bind (
|
||||
&PeerImp::handleVerifyTimer,
|
||||
shared_from_this (), beast::asio::placeholders::error)));
|
||||
|
||||
if (err)
|
||||
{
|
||||
m_journal.error << "Failed to set verify timer.";
|
||||
detach ("c2");
|
||||
return;
|
||||
}
|
||||
|
||||
m_socket->next_layer <NativeSocketType>().async_connect (
|
||||
beast::IPAddressConversion::to_asio_endpoint (m_remoteAddress),
|
||||
m_strand.wrap (std::bind (&PeerImp::onConnect,
|
||||
shared_from_this (), beast::asio::placeholders::error)));
|
||||
}
|
||||
|
||||
public:
|
||||
/** Current state */
|
||||
enum State
|
||||
@@ -201,7 +148,7 @@ public:
|
||||
std::list<uint256> m_recentTxSets;
|
||||
mutable std::mutex m_recentLock;
|
||||
|
||||
boost::asio::deadline_timer m_timer;
|
||||
boost::asio::deadline_timer timer_;
|
||||
|
||||
std::vector<uint8_t> m_readBuffer;
|
||||
std::list<Message::pointer> mSendQ;
|
||||
@@ -217,13 +164,20 @@ public:
|
||||
// True if close was called
|
||||
bool m_was_canceled;
|
||||
|
||||
|
||||
|
||||
boost::asio::streambuf read_buffer_;
|
||||
boost::optional <basic_message> http_message_;
|
||||
boost::optional <basic_message::parser> http_parser_;
|
||||
boost::optional <beast::http::basic_message> http_message_;
|
||||
boost::optional <beast::http::basic_message::parser> http_parser_;
|
||||
message_stream message_stream_;
|
||||
|
||||
boost::asio::streambuf write_buffer_;
|
||||
bool write_pending_;
|
||||
|
||||
std::unique_ptr <LoadEvent> load_event_;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** New incoming peer from the specified socket */
|
||||
PeerImp (
|
||||
NativeSocketType&& socket,
|
||||
@@ -250,10 +204,11 @@ public:
|
||||
, m_clusterNode (false)
|
||||
, m_minLedger (0)
|
||||
, m_maxLedger (0)
|
||||
, m_timer (m_owned_socket.get_io_service())
|
||||
, timer_ (m_owned_socket.get_io_service())
|
||||
, m_slot (slot)
|
||||
, m_was_canceled (false)
|
||||
, message_stream_(*this)
|
||||
, write_pending_ (false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -288,10 +243,11 @@ public:
|
||||
, m_clusterNode (false)
|
||||
, m_minLedger (0)
|
||||
, m_maxLedger (0)
|
||||
, m_timer (io_service)
|
||||
, timer_ (io_service)
|
||||
, m_slot (slot)
|
||||
, m_was_canceled (false)
|
||||
, message_stream_(*this)
|
||||
, write_pending_ (false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -313,22 +269,66 @@ public:
|
||||
|
||||
void getLedger (protocol::TMGetLedger& packet);
|
||||
|
||||
private:
|
||||
//
|
||||
// i/o
|
||||
// client role
|
||||
//
|
||||
|
||||
void
|
||||
start_read();
|
||||
do_connect();
|
||||
|
||||
void
|
||||
on_read_detect (error_code ec, std::size_t bytes_transferred);
|
||||
on_connect (error_code ec);
|
||||
|
||||
beast::http::basic_message
|
||||
make_request();
|
||||
|
||||
void
|
||||
on_read_http (error_code ec, std::size_t bytes_transferred);
|
||||
on_connect_ssl (error_code ec);
|
||||
|
||||
void
|
||||
on_write_http_request (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
void
|
||||
on_read_http_response (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
//
|
||||
// server role
|
||||
//
|
||||
|
||||
void
|
||||
do_accept();
|
||||
|
||||
void
|
||||
on_accept_ssl (error_code ec);
|
||||
|
||||
void
|
||||
on_read_http_detect (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
void
|
||||
on_read_http_request (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
beast::http::basic_message
|
||||
make_response (beast::http::basic_message const& req);
|
||||
|
||||
void
|
||||
on_write_http_response (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
//
|
||||
// protocol
|
||||
//
|
||||
|
||||
void
|
||||
do_protocol_start();
|
||||
|
||||
void
|
||||
on_read_protocol (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
void
|
||||
on_write_protocol (error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// abstract_protocol_handler
|
||||
@@ -354,6 +354,7 @@ public:
|
||||
on_message_end (std::uint16_t type,
|
||||
std::shared_ptr <::google::protobuf::Message> const& m) override;
|
||||
|
||||
// message handlers
|
||||
error_code on_message (std::shared_ptr <protocol::TMHello> const& m) override;
|
||||
error_code on_message (std::shared_ptr <protocol::TMPing> const& m) override;
|
||||
error_code on_message (std::shared_ptr <protocol::TMProofWork> const& m) override;
|
||||
@@ -372,6 +373,7 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
State state() const
|
||||
{
|
||||
return m_state;
|
||||
@@ -422,7 +424,7 @@ public:
|
||||
|
||||
mSendQ.clear ();
|
||||
|
||||
(void) m_timer.cancel ();
|
||||
(void) timer_.cancel ();
|
||||
|
||||
if (graceful)
|
||||
{
|
||||
@@ -450,55 +452,6 @@ public:
|
||||
detach ("stop", graceful);
|
||||
}
|
||||
|
||||
/** Outbound connection attempt has completed (not necessarily successfully)
|
||||
|
||||
The connection may fail for a number of reasons. Perhaps we do not have
|
||||
a route to the remote endpoint, or there is no server listening at that
|
||||
address.
|
||||
|
||||
If the connection succeeded, we transition to the `stateConnected` state
|
||||
and move on.
|
||||
|
||||
If the connection failed, we simply disconnect.
|
||||
|
||||
@param ec indicates success or an error code.
|
||||
*/
|
||||
void onConnect (boost::system::error_code ec)
|
||||
{
|
||||
if (m_detaching)
|
||||
return;
|
||||
|
||||
NativeSocketType::endpoint_type local_endpoint;
|
||||
|
||||
if (! ec)
|
||||
local_endpoint = m_socket->this_layer <
|
||||
NativeSocketType> ().local_endpoint (ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
// VFALCO NOTE This log statement looks like ass
|
||||
m_journal.info <<
|
||||
"Connect to " << m_remoteAddress <<
|
||||
" failed: " << ec.message();
|
||||
// This should end up calling onPeerClosed()
|
||||
detach ("hc");
|
||||
return;
|
||||
}
|
||||
|
||||
bassert (m_state == stateConnecting);
|
||||
m_state = stateConnected;
|
||||
|
||||
m_peerFinder.on_connected (m_slot,
|
||||
beast::IPAddressConversion::from_asio (local_endpoint));
|
||||
|
||||
m_socket->set_verify_mode (boost::asio::ssl::verify_none);
|
||||
m_socket->async_handshake (
|
||||
boost::asio::ssl::stream_base::client,
|
||||
m_strand.wrap (std::bind (&PeerImp::handleStart,
|
||||
std::static_pointer_cast <PeerImp> (shared_from_this ()),
|
||||
beast::asio::placeholders::error)));
|
||||
}
|
||||
|
||||
/** Indicates that the peer must be activated.
|
||||
A peer is activated after the handshake is completed and if it is not
|
||||
a second connection from a peer that we already have. Once activated
|
||||
@@ -516,9 +469,9 @@ public:
|
||||
void start ()
|
||||
{
|
||||
if (m_inbound)
|
||||
accept ();
|
||||
do_accept ();
|
||||
else
|
||||
connect ();
|
||||
do_connect ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -773,47 +726,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// We have an encrypted connection to the peer.
|
||||
// Have it say who it is so we know to avoid redundant connections.
|
||||
// Establish that it really who we are talking to by having it sign a
|
||||
// connection detail. Also need to establish no man in the middle attack
|
||||
// is in progress.
|
||||
void handleStart (boost::system::error_code const& ec)
|
||||
{
|
||||
if (m_detaching)
|
||||
return;
|
||||
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
m_journal.info << "Handshake: " << ec.message ();
|
||||
detach ("hs");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_inbound)
|
||||
m_usage = m_resourceManager.newInboundEndpoint (m_remoteAddress);
|
||||
else
|
||||
m_usage = m_resourceManager.newOutboundEndpoint (m_remoteAddress);
|
||||
|
||||
if (m_usage.disconnect ())
|
||||
{
|
||||
detach ("resource");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!sendHello ())
|
||||
{
|
||||
m_journal.error << "Unable to send HELLO to " << m_remoteAddress;
|
||||
detach ("hello");
|
||||
return;
|
||||
}
|
||||
|
||||
start_read();
|
||||
}
|
||||
|
||||
void handleVerifyTimer (boost::system::error_code const& ec)
|
||||
{
|
||||
if (m_detaching)
|
||||
|
||||
1318
src/ripple/overlay/impl/handshake_analyzer.h
Normal file
1318
src/ripple/overlay/impl/handshake_analyzer.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_OVERLAY_MESSAGE_NAME_H_INCLUDED
|
||||
#define RIPPLE_OVERLAY_MESSAGE_NAME_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
|
||||
char const*
|
||||
@@ -49,5 +46,3 @@ protocol_message_name (int type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
36
src/ripple/overlay/impl/peer_info.h
Normal file
36
src/ripple/overlay/impl/peer_info.h
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_OVERLAY_PEER_INFO_H_INCLUDED
|
||||
#define RIPPLE_OVERLAY_PEER_INFO_H_INCLUDED
|
||||
|
||||
#include <beast/http/basic_message.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
struct parsed_request
|
||||
{
|
||||
int version_major;
|
||||
int version_minor;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -39,7 +39,13 @@ public:
|
||||
*/
|
||||
template <class ConstBufferSequence>
|
||||
boost::tribool
|
||||
operator() (ConstBufferSequence const& buffers)
|
||||
operator() (ConstBufferSequence const& buffers);
|
||||
};
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
boost::tribool
|
||||
peer_protocol_detector::operator() (
|
||||
ConstBufferSequence const& buffers)
|
||||
{
|
||||
std::array <std::uint8_t, 6> data;
|
||||
auto const n (boost::asio::buffer_copy (
|
||||
@@ -61,7 +67,6 @@ public:
|
||||
return true;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
68
src/ripple/overlay/tests/peer_info.test.cpp
Normal file
68
src/ripple/overlay/tests/peer_info.test.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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/overlay/impl/peer_info.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <beast/http/rfc2616.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class peer_info_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Parse a comma delimited list of strings
|
||||
// Leading and trailing whitespace is removed from each element
|
||||
static
|
||||
std::vector <std::string>
|
||||
parse_list (std::string const& value)
|
||||
{
|
||||
std::vector <std::string> list;
|
||||
auto first (value.begin());
|
||||
auto last (value.end());
|
||||
for(;;)
|
||||
{
|
||||
auto const found (std::find (first, last, ','));
|
||||
if (found != first)
|
||||
{
|
||||
auto p0 (first);
|
||||
auto p1 (found - 1);
|
||||
|
||||
}
|
||||
if (found == last)
|
||||
break;
|
||||
first = found + 1;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
expect (beast::http::rfc2616::trim("x") == "x");
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(peer_info,overlay,ripple);
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -25,3 +25,5 @@
|
||||
#include <ripple/overlay/impl/PeerImp.cpp>
|
||||
#include <ripple/overlay/impl/PeerDoor.cpp>
|
||||
|
||||
#include <ripple/overlay/tests/peer_info.test.cpp>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user