aboutsummaryrefslogtreecommitdiff
path: root/tests/unit_tests/net.cpp
diff options
context:
space:
mode:
authorLee Clagett <code@leeclagett.com>2019-05-16 16:34:22 -0400
committerLee Clagett <code@leeclagett.com>2019-07-17 14:22:37 +0000
commit3b24b1d082da28da15dc5e3aeaa0ebebe7758f2f (patch)
tree04c19819bc99545f0472be8812c850ed1a433bfa /tests/unit_tests/net.cpp
parentAdd ref-counted buffer byte_slice. Currently used for sending TCP data. (diff)
downloadmonero-3b24b1d082da28da15dc5e3aeaa0ebebe7758f2f.tar.xz
Added support for "noise" over I1P/Tor to mask Tx transmission.
Diffstat (limited to '')
-rw-r--r--tests/unit_tests/net.cpp396
1 files changed, 396 insertions, 0 deletions
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index 3acf75f3b..f24ffb45c 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -26,6 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <algorithm>
#include <atomic>
#include <boost/archive/portable_binary_oarchive.hpp>
#include <boost/archive/portable_binary_iarchive.hpp>
@@ -36,13 +37,22 @@
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/endian/conversion.hpp>
+#include <boost/range/adaptor/sliced.hpp>
+#include <boost/range/combine.hpp>
#include <boost/system/error_code.hpp>
#include <boost/thread/thread.hpp>
+#include <boost/uuid/nil_generator.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/uuid/uuid.hpp>
+#include <cstdint>
#include <cstring>
#include <functional>
#include <gtest/gtest.h>
+#include <map>
#include <memory>
+#include <type_traits>
+#include "net/dandelionpp.h"
#include "net/error.h"
#include "net/net_utils_base.h"
#include "net/socks.h"
@@ -857,3 +867,389 @@ TEST(socks_connector, timeout)
EXPECT_THROW(sock.get().is_open(), boost::system::system_error);
}
+TEST(dandelionpp_map, traits)
+{
+ EXPECT_TRUE(std::is_default_constructible<net::dandelionpp::connection_map>());
+ EXPECT_TRUE(std::is_move_constructible<net::dandelionpp::connection_map>());
+ EXPECT_TRUE(std::is_move_assignable<net::dandelionpp::connection_map>());
+ EXPECT_FALSE(std::is_copy_constructible<net::dandelionpp::connection_map>());
+ EXPECT_FALSE(std::is_copy_assignable<net::dandelionpp::connection_map>());
+}
+
+TEST(dandelionpp_map, empty)
+{
+ const net::dandelionpp::connection_map mapper{};
+
+ EXPECT_EQ(mapper.begin(), mapper.end());
+ EXPECT_EQ(0u, mapper.size());
+
+ const net::dandelionpp::connection_map cloned = mapper.clone();
+ EXPECT_EQ(cloned.begin(), cloned.end());
+ EXPECT_EQ(0u, cloned.size());
+}
+
+TEST(dandelionpp_map, zero_stems)
+{
+ std::vector<boost::uuids::uuid> connections{6};
+ std::generate(connections.begin(), connections.end(), boost::uuids::random_generator{});
+
+ net::dandelionpp::connection_map mapper{connections, 0};
+ EXPECT_EQ(mapper.begin(), mapper.end());
+ EXPECT_EQ(0u, mapper.size());
+
+ for (const boost::uuids::uuid& connection : connections)
+ EXPECT_TRUE(mapper.get_stem(connection).is_nil());
+
+ EXPECT_FALSE(mapper.update(connections));
+ EXPECT_EQ(mapper.begin(), mapper.end());
+ EXPECT_EQ(0u, mapper.size());
+
+ for (const boost::uuids::uuid& connection : connections)
+ EXPECT_TRUE(mapper.get_stem(connection).is_nil());
+
+ const net::dandelionpp::connection_map cloned = mapper.clone();
+ EXPECT_EQ(cloned.end(), cloned.begin());
+ EXPECT_EQ(0u, cloned.size());
+}
+
+TEST(dandelionpp_map, dropped_connection)
+{
+ std::vector<boost::uuids::uuid> connections{6};
+ std::generate(connections.begin(), connections.end(), boost::uuids::random_generator{});
+ std::sort(connections.begin(), connections.end());
+
+ // select 3 of 6 outgoing connections
+ net::dandelionpp::connection_map mapper{connections, 3};
+ EXPECT_EQ(3u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ {
+ const net::dandelionpp::connection_map cloned = mapper.clone();
+ EXPECT_EQ(3u, cloned.size());
+ ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
+ for (auto elem : boost::combine(mapper, cloned))
+ EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
+ }
+ EXPECT_FALSE(mapper.update(connections));
+ EXPECT_EQ(3u, mapper.size());
+ ASSERT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
+ std::vector<boost::uuids::uuid> in_connections{9};
+ std::generate(in_connections.begin(), in_connections.end(), boost::uuids::random_generator{});
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ std::multimap<boost::uuids::uuid, boost::uuids::uuid> inverse_mapping;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ EXPECT_TRUE(mapping.emplace(connection, out).second);
+ inverse_mapping.emplace(out, connection);
+ used[out]++;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(3u, entry.second);
+
+ for (const boost::uuids::uuid& connection : in_connections)
+ EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
+
+ // drop 1 connection, and select replacement from 1 of unused 3.
+ const boost::uuids::uuid lost_connection = *(++mapper.begin());
+ const auto elem = std::lower_bound(connections.begin(), connections.end(), lost_connection);
+ ASSERT_NE(connections.end(), elem);
+ ASSERT_EQ(lost_connection, *elem);
+ connections.erase(elem);
+
+ EXPECT_TRUE(mapper.update(connections));
+ EXPECT_EQ(3u, mapper.size());
+ ASSERT_EQ(3, mapper.end() - mapper.begin());
+
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_NE(lost_connection, connection);
+ }
+
+ const boost::uuids::uuid newly_mapped = *(++mapper.begin());
+ EXPECT_FALSE(newly_mapped.is_nil());
+ EXPECT_NE(lost_connection, newly_mapped);
+
+ for (auto elems = inverse_mapping.equal_range(lost_connection); elems.first != elems.second; ++elems.first)
+ mapping[elems.first->second] = newly_mapped;
+ }
+ {
+ const net::dandelionpp::connection_map cloned = mapper.clone();
+ EXPECT_EQ(3u, cloned.size());
+ ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
+ for (auto elem : boost::combine(mapper, cloned))
+ EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
+ }
+ // mappings should remain evenly distributed amongst 2, with 3 sitting in waiting
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid& out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ EXPECT_EQ(mapping[connection], out);
+ used[out]++;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(3u, entry.second);
+ }
+ {
+ const net::dandelionpp::connection_map cloned = mapper.clone();
+ EXPECT_EQ(3u, cloned.size());
+ ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
+ for (auto elem : boost::combine(mapper, cloned))
+ EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
+ }
+}
+
+TEST(dandelionpp_map, dropped_connection_remapped)
+{
+ boost::uuids::random_generator random_uuid{};
+
+ std::vector<boost::uuids::uuid> connections{3};
+ std::generate(connections.begin(), connections.end(), random_uuid);
+ std::sort(connections.begin(), connections.end());
+
+ // select 3 of 3 outgoing connections
+ net::dandelionpp::connection_map mapper{connections, 3};
+ EXPECT_EQ(3u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ EXPECT_FALSE(mapper.update(connections));
+ EXPECT_EQ(3u, mapper.size());
+ ASSERT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
+ std::vector<boost::uuids::uuid> in_connections{9};
+ std::generate(in_connections.begin(), in_connections.end(), random_uuid);
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ std::multimap<boost::uuids::uuid, boost::uuids::uuid> inverse_mapping;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ EXPECT_TRUE(mapping.emplace(connection, out).second);
+ inverse_mapping.emplace(out, connection);
+ used[out]++;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(3u, entry.second);
+
+ for (const boost::uuids::uuid& connection : in_connections)
+ EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
+
+ // drop 1 connection leaving "hole"
+ const boost::uuids::uuid lost_connection = *(++mapper.begin());
+ const auto elem = std::lower_bound(connections.begin(), connections.end(), lost_connection);
+ ASSERT_NE(connections.end(), elem);
+ ASSERT_EQ(lost_connection, *elem);
+ connections.erase(elem);
+
+ EXPECT_TRUE(mapper.update(connections));
+ EXPECT_EQ(2u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+
+ for (auto elems = inverse_mapping.equal_range(lost_connection); elems.first != elems.second; ++elems.first)
+ mapping[elems.first->second] = boost::uuids::nil_uuid();
+ }
+ // remap 3 connections and map 1 new connection to 2 remaining out connections
+ in_connections.resize(10);
+ in_connections[9] = random_uuid();
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid& out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ used[out]++;
+
+ boost::uuids::uuid& expected = mapping[connection];
+ if (!expected.is_nil())
+ EXPECT_EQ(expected, out);
+ else
+ expected = out;
+ }
+
+ EXPECT_EQ(2u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(5u, entry.second);
+ }
+ // select 3 of 3 connections but do not remap existing links
+ connections.resize(3);
+ connections[2] = random_uuid();
+ EXPECT_TRUE(mapper.update(connections));
+ EXPECT_EQ(3u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid& out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ used[out]++;
+
+ EXPECT_EQ(mapping[connection], out);
+ }
+
+ EXPECT_EQ(2u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(5u, entry.second);
+ }
+ // map 8 new incoming connections across 3 outgoing links
+ in_connections.resize(18);
+ std::generate(in_connections.begin() + 10, in_connections.end(), random_uuid);
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid& out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ used[out]++;
+
+ boost::uuids::uuid& expected = mapping[connection];
+ if (!expected.is_nil())
+ EXPECT_EQ(expected, out);
+ else
+ expected = out;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(6u, entry.second);
+ }
+}
+
+TEST(dandelionpp_map, dropped_all_connections)
+{
+ boost::uuids::random_generator random_uuid{};
+
+ std::vector<boost::uuids::uuid> connections{8};
+ std::generate(connections.begin(), connections.end(), random_uuid);
+ std::sort(connections.begin(), connections.end());
+
+ // select 3 of 8 outgoing connections
+ net::dandelionpp::connection_map mapper{connections, 3};
+ EXPECT_EQ(3u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ EXPECT_FALSE(mapper.update(connections));
+ EXPECT_EQ(3u, mapper.size());
+ ASSERT_EQ(3, mapper.end() - mapper.begin());
+ {
+ std::set<boost::uuids::uuid> used;
+ for (const boost::uuids::uuid& connection : mapper)
+ {
+ EXPECT_FALSE(connection.is_nil());
+ EXPECT_TRUE(used.insert(connection).second);
+ EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
+ }
+ }
+ std::vector<boost::uuids::uuid> in_connections{9};
+ std::generate(in_connections.begin(), in_connections.end(), random_uuid);
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ EXPECT_TRUE(mapping.emplace(connection, out).second);
+ used[out]++;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(3u, entry.second);
+
+ for (const boost::uuids::uuid& connection : in_connections)
+ EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
+
+ // drop all connections
+ connections.clear();
+
+ EXPECT_TRUE(mapper.update(connections));
+ EXPECT_EQ(0u, mapper.size());
+ EXPECT_EQ(3, mapper.end() - mapper.begin());
+ }
+ // remap 7 connections to nothing
+ for (const boost::uuids::uuid& connection : boost::adaptors::slice(in_connections, 0, 7))
+ EXPECT_TRUE(mapper.get_stem(connection).is_nil());
+
+ // select 3 of 30 connections, only 7 should be remapped to new indexes (but all to new uuids)
+ connections.resize(30);
+ std::generate(connections.begin(), connections.end(), random_uuid);
+ EXPECT_TRUE(mapper.update(connections));
+ {
+ std::map<boost::uuids::uuid, std::size_t> used;
+ for (const boost::uuids::uuid& connection : in_connections)
+ {
+ const boost::uuids::uuid& out = mapper.get_stem(connection);
+ EXPECT_FALSE(out.is_nil());
+ used[out]++;
+ }
+
+ EXPECT_EQ(3u, used.size());
+ for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ EXPECT_EQ(3u, entry.second);
+ }
+}